0

別のTCPソケットの問題に直面しています。私は同様の問題に対する答えをたくさんの質問に読み通しましたが、私の問題はどういうわけか異なります。

JavaクライアントとC++サーバーがあります。別のマシンを使用するまでは、すべてが期待どおりに進みます(これまでの他の問題と同じです)。クライアントからのメッセージがTCPバッファーでスタックしているようです。最終的にソケットを閉じると、すべてがサーバーに送信されます。ただし、これらの単一メッセージは制御メッセージであるため、すぐに送信する必要があります。私が読んだ限り、これは予想される動作ですが、信頼できる制御メッセージを送信するにはどうすればよいですか。

メッセージを強制的に送信する方法はありますか?(何も送信せずに、ソケットを数分間開いたままにしておくことができます。)

何か問題がありますか?(次のコードを参照してください)

REALフラッシュを実行するには、毎回ソケットを閉じる必要がありますか?

代わりにUDPを使用し、追加のプロトコル作業を行う必要がありますか?

Javacode:

mSocketSend = new Socket();
mSocketSend.connect(new InetSocketAddress(mServerIp, mSocketPortSend), mTimeOut);
PrintWriter pw = new PrintWriter(mSocketSend.getOutputStream(), true);
pw.println(data);

C ++コード:

   opening socket...(i leave that)
   char* buffer = new char[1024];
   int rc = recv(mConnectedSocket, buf, 1024, 0);

もっと欲しいなら。書いてください。私はほとんどすべてを省きました。^^私はそれが適切だとは思いません。コミュニケーションは通常うまくいきました..エラーはまったくありませんでした。つまり、これだけのTCPBufferです。

区切り文字やメッセージの長さなどがあるはずです。しかし実際には、送信されないメッセージの長さは役に立ちません。^^

ご協力いただきありがとうございます。

編集#01コードの全体:

mSocket->createSocketServer(22);
    char* buffer = new char[1024];
 while(true){

        int numberBytes = mSocket->receiveChars(buffer, 1024);

        if (numberBytes > 0){
            uninterestingHandlingFunction(buffer);
        }else{
            mSocket->createSocketServer(22);
        }
    }

bool Socket::createSocketServer(u_short port)
{
    if (mConnectedSocket != INVALID_SOCKET)
    {
        closesocket(mConnectedSocket);
    }

    if (s == INVALID_SOCKET)
    {
        WSADATA wsa;

        if (WSAStartup(MAKEWORD(2,0), &wsa) != 0)
            return 0;

        s = socket(AF_INET, SOCK_STREAM, 0);
        if (s == INVALID_SOCKET)
            return 0;

        SOCKADDR_IN addr;
        memset(&addr, 0, sizeof(SOCKADDR_IN));
        addr.sin_family=AF_INET;
        addr.sin_port=htons(port);
        addr.sin_addr.s_addr=ADDR_ANY;

        if (bind(s, (SOCKADDR*)&addr, sizeof(SOCKADDR_IN)) == SOCKET_ERROR)
        {
            s = INVALID_SOCKET;
        } else if (listen(s, 10) == SOCKET_ERROR)
        {
            s = INVALID_SOCKET;
        }

        if (s == INVALID_SOCKET)
        {
            closesocket(s);
            return 0;
        }
    }
    mConnectedSocket = accept(s, NULL, NULL);

    if (mConnectedSocket == INVALID_SOCKET)
    {
        closesocket(s);
        return 0;
    }
    return 1;
}

int Socket::receiveChars(char* buf, unsigned maxSize)
{
    if (mConnectedSocket == INVALID_SOCKET)
        return -1;

    int rc = recv(mConnectedSocket, buf, maxSize, 0);
    if (rc == SOCKET_ERROR)
    {
        std::cout << "Socket: error " << WSAGetLastError() << std::endl;
    }
    return rc;
}

あなたはそれが欲しかった…。

編集#2もう一度試してみてください

私が試したことが他にもいくつかあります。最初:この問題は、実際のネットワークを介して毎回接続されているデバイスでは発生しません。->クライアントとサーバーの完全な再起動->問題は発生しません->クライアントとサーバーの完全な再起動->問題が発生します

悲しいことに、私はこの習慣から何を取るべきかわかりません。

私が偶然見つけたもう1つのことは、バインドおよびリッスンソケット(コードSOCKET)です。このソケットは接続をリッスンし、作業スレッドが新しい接続を必要とする場合(起動時または前の接続が閉じた場合)、ソケットsはrecvのためにmConnectedSocketに次のキュー接続を提供し、他の接続は処理中にバックログされます。Javaビューから:ソケットが接続されています(デバイスA)。次のソケット(デバイスB)が接続を試みます。->接続の成功(これが実際に発生した場合はコードで適切に制御されます)->その後に自然な問題でデータを送信します。(ソケットはまだc ++側のバックログにあります)

さて、これは私が経験した習慣に変えるのは難しいです。自分の考えを表現しようと思います。Javaside:PrintWriterが作成されます。データが供給され、フラッシュされます。接続が完全に確立されていないため(C ++側に追加のconnectedSocketはありません)。フラッシュが機能しません。そして、onCloseは、ソケットが最終的にその内容をフラッシュします。

もしそう思うなら、黙ってくださいと言ってください。「接続がバックログされている」が実際に実装で何を意味するのか、私にはよくわかりません^^

接続ごとに新しいスレッドを開く必要があることはわかっていますが、現時点ではできません。したがって、このサーバーコードに固執します。

4

7 に答える 7

2

データをプッシュするflush()を実行する必要があります。

于 2012-05-18T20:37:48.687 に答える
1
PrintWriter.flush();

または、自動フラッシュ機能を備えたライターを使用してください。

また、サーバーが1024文字全体ではなく行を読み取ることを確認する必要があります(\ nまで)が、recv()が何をするのかわからないので、それについてはわかりません。

于 2012-05-18T20:46:13.883 に答える
1

修正しました。ちょっと恥ずかしい...私の編集で気付いたバックログは確かに問題でした。一度に2つのクライアントがサーバーに接続すると、2つ目はバックログされ、最初の切断時にメッセージが処理されます。

さらに(ここに手がかりがあります)

前に述べたように、そのアンドロイドJavaクライアント。Java側には、C++サーバーからデータを受信するための別のスレッドがあります。このソケットは別のポートに接続します。しかし、設定アクティビティで接続するポートとIPアドレスを設定し、他のソケットのポートがデフォルト値として不良でした(issuesocketの場合と同じ、間違った変数が取得されました)。したがって、このソケットが最初に接続され、issuesocketがに接続されます。やり残し。このデフォルト値は、別のIPアドレスを設定するための設定を入力した場合にのみ使用されます(たとえば、ローカルホストではなくリモートホストに接続する場合)

信じられないほどの状況...私も設定を書きませんでした...

WIRESHARKはこれを修正したでしょう。

于 2012-05-24T21:34:50.767 に答える
0

実際には、問題は受信側にある可能性がありrecv、ループ内にある必要があります(この例についてはグーグルで検索できます)。への各呼び出しがあまり得られないという保証はありませんrecv。Javaサイトでデータをフラッシュしていることがわかっている場合は、それがおそらく問題です。

于 2012-05-18T20:55:34.063 に答える
0
PrintWriter pw = new PrintWriter(mSocketSend.getOutputStream(), true);
pw.println(data);
pw.flush();
于 2012-05-18T20:47:47.560 に答える
0

自動フラッシュを使用していて、明示的な使用を試みたためflush()

inputStreamを開かないことが原因である可能性があります。getInputStream()同様に試してみてください。

それ以外の場合は、試しましたか:

  1. 使用しないdiffはありますが、コンストラクターconnectで直接パラメーターを指定するだけですか?Socket

  2. setTcpNoDelayソケット上(ただし、数分の遅延は発生しないはずです!!)?

于 2012-05-18T20:49:24.977 に答える
0

ループが正しくコーディングされていません。新しいrecv()はすべて、前のものを上書きします。オフセットパラメータを進める必要があります。

于 2012-05-19T12:10:58.340 に答える