简体   繁体   English

为什么InputStreamReader无法读取websocket包的内容?

[英]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. 为了了解websocket的行为,我在Java中创建了一个简单的SocketServer来交换消息。 The server is expected to follow the operations as: 服务器应遵循以下操作:

1) Listening at port 8080 1)在8080端口监听

2) A websocket handshake message generated manually on the browser client and received by the server. 2)在浏览器客户端上手动生成并由服务器接收的Websocket握手消息。

3) Construct a response to the handshake message and reply to the client 3)构建对握手消息的响应并回复客户端

4) Read out actually websocket info bytes with the same connection. 4)实际读取具有相同连接的websocket信息字节。

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. 该问题已在步骤4发生。当服务器以握手消息响应时,InputStreamReader不再能够接收任何新消息。 It blocked at the readline() method even though the client has sent the message already. 即使客户端已经发送了消息,它也会在readline()方法上阻止。 From wireshark, I can see the client sent message and server respond ack. 从wireshark中,我可以看到客户端发送了消息并且服务器响应了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: Wireshark屏幕截图:

The tcp stream trace tcp流跟踪

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,问题在于响应握手中缺少空白行以指示消息的结尾。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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