2

私は(学習目的で)WebSocketサーバーを実装しており、ハンドシェイクを正しく処理しています(websocket.onopenが呼び出されるため、ハンドシェイクが成功したことを意味すると思います)が、クライアント(ブラウザー)がハンドシェイク後にメッセージを送信すると、サーバーはそれを受信しません。

Chromeの開発者ツールを使用すると、すべてのヘッダーが正しく受信され、エラーがスローされていないことがわかります。また、JavaでreadLine()が起動しないにもかかわらず、「h​​ello」を送信したことも示されています。

私のコードの何が問題になっていますか?

編集1: Webページを更新すると、ServerSocketが最後の接続からデータを受信することを発見しました(更新が強制終了されたばかりです)。なぜこれがそれを受け取る唯一の方法なのですか?

編集2:ハンドシェイク後にクライアントにメッセージを送信でき、クライアントがメッセージを受信したが、それでもサーバーがクライアントのメッセージを受信しないこともわかりました。私は次のようにクライアントにメッセージを送信しました:

byte[] message = new byte[ 7 ];
message[ 0 ] = new Integer(129).byteValue();
message[ 1 ] = new Integer(5).byteValue();
byte[] raw = "hello".getBytes();
message[ 2 ] = raw[ 0 ];
message[ 3 ] = raw[ 1 ];
message[ 4 ] = raw[ 2 ];
message[ 5 ] = raw[ 3 ];
message[ 6 ] = raw[ 4 ];
outStream.write( message);
out.println();

HTMLページ

<!DOCTYPE html>
<html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> 
    <title>WebSocket Test</title></head>

    <body>
        <script>
            try
            {
                function writeToScreen(message)
                {
                    var p = document.createElement( "p" );
                    p.innerHTML = message;
                    document.getElementsByTagName( "body" )[ 0 ].appendChild( p );
                }

                function onOpen(evt)
                {
                    writeToScreen( "opened" );
                    doSend( "hello" );
                    //We reach here but the server never recieves the message! (and bufferedAmount == 0)
                    writeToScreen( "sent: " + websocket.bufferedAmount );
                }
                function onClose(evt)
                {
                    alert( "closed" );
                    websocket.close();
                }
                function onMessage(evt)
                {
                    alert( "Message: " + evt.data );
                }
                function onError(evt)
                {
                    alert( "Error: " + evt );
                }

                function doSend (message)
                {   
                    websocket.send( message );
                }

                //PUT IN YOUR OWN LOCAL IP ADDRESS HERE TO GET IT TO WORK
                var websocket = new WebSocket( "ws://192.168.1.19:4444/" );
                websocket.onopen = onOpen;
                websocket.onclose = onClose;
                websocket.onmessage = onMessage;
                websocket.onerror = onError;

            }
            catch(e)
            {
            }
        </script>
    </body>
</html>

JAVAコード

import java.net.*;
import java.io.*;
import java.security.*;

public class WebListener
{
    public static void main(String[] args) throws Exception
    {
        ServerSocket serverSocket = null;
        boolean listening = true;

        try {
            serverSocket = new ServerSocket(4444);
        } catch (IOException e) {
            System.err.println("Could not listen on port: 4444.");
            System.exit(-1);
        }

        while (listening) new ServerThread(serverSocket.accept()).start();

        serverSocket.close();
    }
}

class ServerThread extends Thread {
    private Socket socket = null;

    public ServerThread(Socket socket) {
        super("ServerThread");
        this.socket = socket;
    }

    public void run() {

        try {
            OutputStream outStream = null;
            PrintWriter out = new PrintWriter( outStream = socket.getOutputStream(), true);
            BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream()));

            String inputLine, outputLine;

            //Handle the headers first
            doHeaders( out, in );

            //Now read anything they have to send
            while ( ( inputLine = in.readLine() ) != null )
            {
                //WE NEVER REACH HERE!
                System.out.println( inputLine );
            }

            out.close();
            in.close();
            socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void doHeaders(PrintWriter out, BufferedReader in) throws Exception
    {
        String inputLine = null;
        String key = null;

        //Read the headers
        while ( ( inputLine = in.readLine() ) != null )
        {
            //Get the key
            if ( inputLine.startsWith( "Sec-WebSocket-Key" ) ) key = inputLine.substring( "Sec-WebSocket-Key: ".length() );

            //They're done
            if ( inputLine.equals( "" ) ) break;
        }

        //We need a key to continue
        if ( key == null ) throw new Exception( "No Sec-WebSocket-Key was passed!" );

        //Send our headers
        out.println( "HTTP/1.1 101 Web Socket Protocol Handshake\r" );
        out.println( "Upgrade: websocket\r" );
        out.println( "Connection: Upgrade\r" );
        out.println( "Sec-WebSocket-Accept: " + createOK( key ) + "\r" );
        out.println( "\r" );
    }

    public String createOK(String key) throws NoSuchAlgorithmException, UnsupportedEncodingException, Exception
    {
        String uid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
        String text = key + uid;

        MessageDigest md = MessageDigest.getInstance( "SHA-1" );
        byte[] sha1hash = new byte[40];
        md.update( text.getBytes("iso-8859-1"), 0, text.length());
        sha1hash = md.digest();

        return new String( base64( sha1hash ) );
    }

    public byte[] base64(byte[] bytes) throws Exception
    {
        ByteArrayOutputStream out_bytes = new ByteArrayOutputStream();
        OutputStream out = new Base64.OutputStream(out_bytes); //Using http://iharder.net/base64
        out.write(bytes);
        out.close();
        return out_bytes.toByteArray();
    }

    private String convertToHex(byte[] data) { 
        StringBuffer buf = new StringBuffer();
        for (int i = 0; i < data.length; i++) { 
            int halfbyte = (data[i] >>> 4) & 0x0F;
            int two_halfs = 0;
            do { 
                if ((0 <= halfbyte) && (halfbyte <= 9)) 
                    buf.append((char) ('0' + halfbyte));
                else 
                    buf.append((char) ('a' + (halfbyte - 10)));
                halfbyte = data[i] & 0x0F;
            } while(two_halfs++ < 1);
        } 
        return buf.toString();
    } 
}
4

2 に答える 2

1

コードWebListenerはWindowsで実行する必要があり、line.separatorはCRLFであることがわかります。

    byte[] lineSeperator=System.getProperty("line.separator").getBytes();
    System.out.println("line seperator: "+Arrays.toString(lineSeperator));

応答ヘッダー内

    out.println( "Header xxxx"+ "\r" );

したがって、ヘッダーは\ r \ r\nで終了します

HTTPごとrfc2616

   Response      = Status-Line               ; Section 6.1
                   *(( general-header        ; Section 4.5
                    | response-header        ; Section 6.2
                    | entity-header ) CRLF)  ; Section 7.1
                   CRLF
                   [ message-body ]          ; Section 7.2

クライアントは\r\ r\nでヘッダーをデコードできません。

于 2012-08-24T05:34:17.463 に答える
1

WebSocketメッセージはによって終了されないため、メッセージを読み取るために\r\n使用することはできません。メッセージの作成方法については、仕様のデータフレーミングのin.readline()セクションを参照してください。

クライアント(ブラウザ)からサーバーへのテキストメッセージの場合、メッセージの形式は次のとおりです。

  • (バイト)0x81
  • メッセージの長さとメッセージ本文がマスクされているかどうかを示す1、3、または9バイトの構造。(ブラウザからのメッセージは常にマスクする必要があります。)
  • 4バイトマスク
  • メッセージ(utf-8エンコード)

検索できるメッセージ終了マーカーはありません。ペイロードの長さを把握するには、クライアント要求の最初の数バイトを読み取る必要があります。

于 2012-08-24T08:19:27.317 に答える