java - 为什么我的服务器从来没有收到 WebSocket 发送的信息?

标签 java javascript websocket

我正在实现一个 WebSocket 服务器(出于学习目的),并且我让它正确处理握手(websocket.onopen 被调用,所以我认为这意味着握手成功),但是,当客户端(浏览器)在握手后发送一条消息,服务器永远不会收到它。

使用 Chrome 的开发人员工具,我可以看到所有 header 均已正确接收,并且没有引发任何错误。它还说它发送了“hello”,尽管 readLine() 在 Java 中从未触发。

我的代码有什么问题?

编辑1:我发现,如果我刷新网页,那么(并且只有那时)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();
    } 
}

最佳答案

WebSocket 消息不会由 \r\n 终止,因此您无法使用 in.readline() 读取它们。请参阅data framing规范中有关如何构造消息的部分。

对于从客户端(浏览器)到服务器的文本消息,消息将采用以下形式:

  • (字节)0x81
  • 1、3或9字节结构,指示消息长度以及消息正文是否被屏蔽。 (来自浏览器的消息应始终被屏蔽。)
  • 4 字节掩码
  • 消息(utf-8 编码)

没有可以搜索的消息结束标记。您只需读取客户端请求的前几个字节即可计算出其有效负载的长度。

关于java - 为什么我的服务器从来没有收到 WebSocket 发送的信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12102513/

相关文章:

Java Socket - 将对象绑定(bind)到 IP

java - OncreateView 中的意外 NPE

java - 启用 Carbon SecureVault 后 WSO2 GR 无法启动

java - Dispatcher-servlet 无法映射到 websocket 请求

c# - 我可以强制我的网络套接字不使用 SSL 即使我的网站是在 SSL 下提供服务的吗?

java - 如何从java程序在终端运行命令?

javascript - 在 Javascript/jQuery 中重新启动 setInterval()(没有 clearInterval)

javascript - Meteor renderList 拦截?客户端

javascript - RxJS:可观察对象和单个观察者的递归列表

python - 什么可以关闭 websocket 连接?