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の画面がキャプチャ:
ログ:
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>
HTTPを実装しようとしているなら、RFC 2616と後継者に関する十分な知識が必要です。ここよりもはるかに多くが現れています。広すぎます。 – EJP
私が理解しているように、プロトコルの詳細にかかわらず、リスニングポートにデータが到着した場合、それを読み取ることができると予想しました。たとえそれが意味をなさないかもしれないし、さらに分析が必要な場合でも、到着したパケットでデータバイトを利用できるようにする必要があります。 –
それは正しいです。それは読み出すことができます。 'readLine()'がnullを返すと、あなたのエラーの1つが続きます。つまり、ストリームの終わりに永遠にループします。 – EJP