0

アプリケーションにチャットを実装する必要がありました。サーバーへの接続は、ソケットを使用して行われます。そのサーバーに登録する必要があり、サーバーは応答でそれを認識します。

これを BufferedWriter を使用してコマンドを送信する 1 つのメソッドに実装し、データがなくなるまで入力ストリームから読み取りを開始します。

サーバーの応答を正しく読みました。ただし、2 番目の呼び出しから負の値を取得することはないためin.read、メソッドは while ループ (その呼び出しを行う条件文) でブロックされたままになります。

これはソケットでどのように行うべきですか? 私は通常、ファイルやその他の入力ストリームで問題なくこれを行います。

読み取るはずのバイトのみを読み取る必要がある場合、次のいずれかを行う必要があることを意味しますか?

  • サーバー応答の長さを事前に知っていますか?
  • または、サーバーにコードを送信させて、応答の送信が完了したことを通知しますか?

現在、私は次のことを行っています:

private String sendSocketRequest(String request, boolean skipResponse) throws ChatException {
    if (!isConnected()) openConnection();

    try {
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(
                                     socket.getOutputStream()), 2048);
        out.append(request);
        out.flush();
        out = null;
    } catch (IOException e) {
        LogHelper.error("Unable to send socket request: " + request, e);
        throw new ChatException("Unable to send socket request: " + request, e);
    }

    try {
        BufferedReader in = new BufferedReader(new InputStreamReader(
                                     socket.getInputStream()), 2048);
        StringBuffer response = new StringBuffer();
        char[] buffer = new char[2048];
        int charsRead = -1;

// >>>>>>>> This is where it gets blocked <<<<<<<<<

        while ((charsRead = in.read(buffer)) >= 0) {
            if (charsRead > 0) response.append(new String(buffer, 0, charsRead));
        }
        return response.toString();
    } catch (IOException e) {
        LogHelper.error("Unable to read socket response: " + request, e);
        throw new ChatException("Unable to read socket response: " + request, e);
    }
}

サーバーへの接続は、次の方法で行われます。

public synchronized void openConnection() throws ChatException {
    try {
        socket = new Socket(Constants.API_CHAT_SERVER_ADDRESS, Constants.API_CHAT_SERVER_PORT);
        socket.setKeepAlive(true);

        LogHelper.debug("CHAT      >> Connected to the chat server: " + Constants.API_CHAT_SERVER_ADDRESS);
    } catch (UnknownHostException e) {
        LogHelper.error("Unable to open chat connection", e);
        throw new ChatException("Unable to open chat connection", e);
    } catch (IOException e) {
        LogHelper.error("Unable to open chat connection", e);
        throw new ChatException("Unable to open chat connection", e);
    }
}
4

2 に答える 2

1

ソケットベースの接続で送受信されるデータの量はプロトコルに依存し、TCP/IP スタックには認識されず、アプリケーション層だけに認識されます。

使用されるプロトコルは開発者に依存します... ;-)だからあなたの質問に来ます:

読み取るはずのバイトのみを読み取る必要がある場合、次のいずれかを行う必要があることを意味しますか?

  • サーバー応答の長さを事前に知っていますか?

はい、これは 1 つの可能性です。

  • または、サーバーにコードを送信させて、応答の送信が完了したことを通知しますか?

はい、これは別の可能性です。一般的なマーカーは\nまたは\r\nです。NUL/'\0'文字も意味があるかもしれません。

3 番目のオプションは、各データ チャンクの前に、これから来るバイト数を表す一定のバイト数を付けることです。

于 2012-11-19T18:09:58.687 に答える
1

バイトを処理する代わりに、たとえばMessageクラスのようなアドホック クラスのインスタンスを処理する方が簡単かもしれません。

サーバー:

// Streams
protected ObjectInputStream fromBuffer = null;
protected ObjectOutputStream toBuffer = null;

// Listening for a new connection
ServerSocket serverConn = new ServerSocket(TCP_PORT);
socket = serverConn.accept();
toBuffer = new ObjectOutputStream(socket.getOutputStream());
fromBuffer = new ObjectInputStream(socket.getInputStream());

// Receiving a new Message object
Message data = (Message)fromBuffer.readObject();

次に、クライアントは次のように単純にメッセージを送信します。

// Sending a message
Message data = new Message("Hello");
toBuffer.writeObject(data);

メッセージは、そのメンバーがSerializableインターフェイスを実装している限り、必要に応じて複雑にすることができます。

于 2012-11-19T18:44:17.900 に答える