Closed earlywusa closed 7 years ago
尝试用java socket实现简单的websocket信息交换,我的理解是分成以下的简单几步: 1)建立ServerSocket,并且监听 8080 (自己制定的端口) 2)用javascript建立Websocket,并发送 handshake 信息。 3)ServerSocket 收到 握手请求,发送回复 4)Websocket收到握手回复,验证sec-websocket-accept header,如果正确,发送消息数据包 5)ServerSocket 收到数据包,进行websocket数据包格式验证,读取payload. 我的问题是出在第5步, 验证的sec-websocket-accept显示正确,但回复的数据包在inputstream上面读不出来。 感觉就是readline()命令完全没有收到任何byte,哪怕是encoded的数据, 一直wait在数据流上面。 从wireshark上来看,client端已经发送了数据,server也返回了ack回复, 说明收到了,可是stream就是没有消息。。
以下是全部log, readline在发了握手回复之后再也没有收到inputstream的消息。 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: keY/5XS7qWTLVop5h88axw== 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: /f4sn4/rmtjrgIUTRUhJPkS6KoQ=
这里是chrome的截图,显示收到了握手回复 这里是wireshark的tcp stream 截图和package sequence的截图
以下是我的test server 代码。 ` package com.early.main;
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; import java.util.concurrent.TimeUnit; import org.apache.commons.codec.binary.Base64; import org.apache.commons.codec.digest.DigestUtils; import com.early.socket.message.HttpMessage; import com.early.socket.message.Message; 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"); //<--- 这行修复了问题 //log.debug(sb.toString()); return sb.toString(); } }
`
<!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>
类似的情况在stackoverflow上也有一个帖子。https://stackoverflow.com/q/10742247/7466185 在网页关闭的时候, inputstream可以读出来数据了。 这个好奇怪。 感觉就像是websocket 没有flush一样。 有没有谁对前端websocket比较熟的可以给出一些建议
问题找到了。。少打了一个空行去标识信息结束。。
尝试用java socket实现简单的websocket信息交换,我的理解是分成以下的简单几步: 1)建立ServerSocket,并且监听 8080 (自己制定的端口) 2)用javascript建立Websocket,并发送 handshake 信息。 3)ServerSocket 收到 握手请求,发送回复 4)Websocket收到握手回复,验证sec-websocket-accept header,如果正确,发送消息数据包 5)ServerSocket 收到数据包,进行websocket数据包格式验证,读取payload. 我的问题是出在第5步, 验证的sec-websocket-accept显示正确,但回复的数据包在inputstream上面读不出来。 感觉就是readline()命令完全没有收到任何byte,哪怕是encoded的数据, 一直wait在数据流上面。 从wireshark上来看,client端已经发送了数据,server也返回了ack回复, 说明收到了,可是stream就是没有消息。。
以下是全部log, readline在发了握手回复之后再也没有收到inputstream的消息。 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: keY/5XS7qWTLVop5h88axw== 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: /f4sn4/rmtjrgIUTRUhJPkS6KoQ=
这里是chrome的截图,显示收到了握手回复 这里是wireshark的tcp stream 截图和package sequence的截图
以下是我的test server 代码。 ` package com.early.main;
`
以下是我javascript websocket 的代码 (github的code格式怎么也没有调整好, 请大家凑合看一下):