2017-07-20 1 views
1

websocketの動作を理解するために、私はメッセージを交換するためにjavaで単純なSocketServerを作成しました。ポート8080なぜInputStreamReaderがwebsocketパッケージの内容を読み取れないのですか?

2)ブラウザクライアントに手動で生成され、サーバによって受信のWebSocketハンドシェイクメッセージで鑑賞)

1:サーバは、以下のように操作に従うことが期待されています。

3)は、ハンドシェイクメッセージへの応答を構築し、クライアント

4)実際のWebSocketの情報は、同じ接続でバイトの読み出しに返信します。

手順4で問題が発生しました。サーバーがハンドシェイクメッセージで応答したとき、InputStreamReaderは新しいメッセージを受信できなくなりました。クライアントがすでにメッセージを送信したとしても、readline()メソッドでブロックされました。 wiresharkから、クライアントが送信したメッセージとサーバーが応答したことがわかります。どんな助けでも感謝します、ありがとう。

更新:私はこの質問が以前に尋ねられたことに気付きました。私は最初に他の投稿の提案を勉強します。

更新:振る舞いはこの記事と同じである:webtabが閉じると Weird websocket behavior: only send data when close the tab 、読み出しストリームは、データパッケージを受け取りました。

wiresharkの画面がキャプチャ:

The tcp stream trace

The packages sequence

ログ:

inputline: GET/HTTP/1.1 
inputline: Host: localhost:8080 
inputline: Connection: Upgrade 
inputline: Pragma: no-cache 
inputline: Cache-Control: no-cache 
inputline: Upgrade: websocket 
inputline: Origin: file:// 
inputline: Sec-WebSocket-Version: 13 
inputline: User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/59.0.3071.115 Safari/537.36 
inputline: Accept-Encoding: gzip, deflate, br 
inputline: Accept-Language: en,zh-TW;q=0.8,zh;q=0.6,zh-CN;q=0.4 
inputline: Sec-WebSocket-Key: Yin4xn04vr9iBH1b2dU15A== 
inputline: Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits 
inputline: 
response: HTTP/1.1 101 Switching Protocols 
Upgrade: websocket 
Connection: Upgrade 
Sec-WebSocket-Accept: +Y9whLTzCdyN1INpAxjkO6yD2Nw= 

サーバソケットコード:

public class EchoServer { 
public static String HTTP_VERSION_HEADER = "HTTP/1.1"; 
public static void main(String[] args) throws IOException { 

    int portNumber = 8080; 

    try (
     ServerSocket serverSocket = 
      new ServerSocket(Integer.parseInt("8080")); 
     Socket clientSocket = serverSocket.accept();  
     PrintWriter out = 
      new PrintWriter(clientSocket.getOutputStream(), true);     
     BufferedReader in = new BufferedReader(
      new InputStreamReader(clientSocket.getInputStream())); 
    ) { 
     String inputLine; 
     StringBuilder sb = new StringBuilder(); 
     while (true) { 
       inputLine = in.readLine(); 
       if(inputLine == null) { 
        System.out.println("input is null"); 
        continue; 
       } 
       System.out.println("inputline: " + inputLine); 
       sb.append(inputLine).append(System.lineSeparator()); 
       if(inputLine.equals("")) { 
         Message msg = new Message(sb.toString(), new Date()); 
         HttpMessage tmpMessage = new HttpMessage(msg.getText(), new Date()); 
         String response = generateHandshakeResponse(tmpMessage); 
         System.out.println("response: " + response); 
         out.println(response); 
         out.flush(); 
       } 
     } 
    } catch (IOException e) { 
     System.out.println("Exception caught when trying to listen on port " 
      + portNumber + " or listening for a connection"); 
     System.out.println(e.getMessage()); 
    } 
} 

private static String generateHandshakeResponse(HttpMessage message) { 
    String webSocketKey = message.getVal(HttpMessage.SEC_WEBSOCKET_KEY); 
    String webSocketAccept = webSocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; 
    byte[] bytes = DigestUtils.sha1(webSocketAccept); 
    String secWebSocketAcceptVal = Base64.encodeBase64String(bytes); 

    StringBuilder sb = new StringBuilder(); 
    sb.append(HTTP_VERSION_HEADER).append(" 101 ").append("Switching Protocols\r\n"); 
    sb.append("Upgrade: websocket\r\n"); 
    sb.append("Connection: Upgrade\r\n"); 
    sb.append("Sec-WebSocket-Accept: ").append(secWebSocketAcceptVal).append("\r\n"); 
    sb.append("\n\n") //<--- this line fixed the problem 
    //log.debug(sb.toString()); 
    return sb.toString(); 
    } 
} 

クライアントコード:たくさんEJPへ

<!doctype html> 
<html lang="en"> 
<head> 
<title>Websocket Client</title> 
</head> 
<body> 
<script> 
var exampleSocket = new WebSocket("ws://localhost:8080"); 
exampleSocket.onopen = function (event) { 
    console.log("connection opened.."); 
    exampleSocket.send("Can you hear me?"); 
}; 
exampleSocket.onmessage = function (event) { 
    console.log(event.data); 
} 

function sendMsg(){ 
    console.log("send message.."); 
    exampleSocket.send("hello hello"); 
} 
</script> 
<button onclick="sendMsg()" title="send">send</button> 
</body> 
</html> 
+1

HTTPを実装しようとしているなら、RFC 2616と後継者に関する十分な知識が必要です。ここよりもはるかに多くが現れています。広すぎます。 – EJP

+1

私が理解しているように、プロトコルの詳細にかかわらず、リスニングポートにデータが到着した場合、それを読み取ることができると予想しました。たとえそれが意味をなさないかもしれないし、さらに分析が必要な場合でも、到着したパケットでデータバイトを利用できるようにする必要があります。 –

+0

それは正しいです。それは読み出すことができます。 'readLine()'がnullを返すと、あなたのエラーの1つが続きます。つまり、ストリームの終わりに永遠にループします。 – EJP

答えて

0

おかげで、問題は、メッセージの終わりを示すために、応答ハンドシェイクで行方不明空白行です。

関連する問題