简体   繁体   中英

Why InputStreamReader cannot read the content of a websocket package?

To understand the behaviour of the websocket, I created a simple SocketServer in java to exchange the messages. The server is expected to follow the operations as:

1) Listening at port 8080

2) A websocket handshake message generated manually on the browser client and received by the server.

3) Construct a response to the handshake message and reply to the client

4) Read out actually websocket info bytes with the same connection.

The problem has happened at step 4. when the server has responded with the handshake message, the InputStreamReader can no longer receive any new message. It blocked at the readline() method even though the client has sent the message already. From wireshark, I can see the client sent message and server respond ack. Any help would be appreciated, thanks.

Update: I just noted this question has been asked before. I will study the suggestions on the other posts first.

Update: The behavior is as same as this post: Weird websocket behavior: only send data when close the tab When the webtab closes, the read stream received the data package.

wireshark screen captures:

The tcp stream trace

The packages sequence

The log:

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=

The server socket code:

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();
    }
}

The client code:

<!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>

非常感谢EJP,问题在于响应握手中缺少空白行以指示消息的结尾。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM