不带 JEE/应用程序服务器的独立 WebSocket 服务器

2022-09-03 14:13:27

我需要在Java SE中实现一个相当简单的WebSocket服务器。它需要做的就是接受连接并存储相应的会话,然后在触发某个事件时向所有连接的客户端发送消息。

我找不到一个教程来了解如何在常规Java SE中执行此操作。所有这些都需要与Maven一起运行,或者将其部署为WAR - 这对于这个项目来说都是不可能的。我需要将其作为 Java SE 桌面应用程序运行。

我找到的教程展示了如何使用 、 和 等注释实现端点。但是,它们都没有解释如何实际初始化服务器。我还需要能够为传入连接指定不同的端口号。@OnOpen@OnMessage@OnClose

我错过了什么吗?我知道人们已经使用WebSocket制作了聊天应用程序,这真的不需要Web应用程序服务器。我也没有使用Maven,为了简单起见,我更愿意保持这种方式。


答案 1

https://github.com/TooTallNate/Java-WebSocket 是Java SE中完整的WebSockets服务器和客户端实现,不需要企业/Web应用程序服务器。


答案 2

Java 11 服务器代码:

package org.treez.server.websocket;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.bind.DatatypeConverter;;

public class WebSocketServer{


    public static void main(String[] args){

        int portNumber = 8000;

        ServerSocket server;
        try {
            server = new ServerSocket(portNumber);
        } catch (IOException exception) {
            throw new IllegalStateException("Could not create web server", exception);
        }


        Socket clientSocket;
        try {
            clientSocket = server.accept(); //waits until a client connects
        } catch (IOException waitException) {
            throw new IllegalStateException("Could not wait for client connection", waitException);
        }

        InputStream inputStream;
        try {
            inputStream  = clientSocket.getInputStream();
        } catch (IOException inputStreamException) {
            throw new IllegalStateException("Could not connect to client input stream", inputStreamException);
        }

        OutputStream outputStream;
        try {
            outputStream  = clientSocket.getOutputStream();
        } catch (IOException inputStreamException) {
            throw new IllegalStateException("Could not connect to client input stream", inputStreamException);
        }

        try {
            doHandShakeToInitializeWebSocketConnection(inputStream, outputStream);
        } catch (UnsupportedEncodingException handShakeException) {
            throw new IllegalStateException("Could not connect to client input stream", handShakeException);
        }


        try {        
            outputStream.write(encode("Hello from Server!"));
            outputStream.flush();
        } catch (UnsupportedEncodingException e) {          
            e.printStackTrace();
        } catch (IOException e) {       
            e.printStackTrace();
        }   

         try {
                printInputStream(inputStream);
            } catch (IOException printException) {
                throw new IllegalStateException("Could not connect to client input stream", printException);
            }

    }

    //Source for encoding and decoding:
    //https://stackoverflow.com/questions/8125507/how-can-i-send-and-receive-websocket-messages-on-the-server-side


    private static void printInputStream(InputStream inputStream) throws IOException {
        int len = 0;            
        byte[] b = new byte[1024];
        //rawIn is a Socket.getInputStream();
        while(true){
            len = inputStream.read(b);
            if(len!=-1){

                byte rLength = 0;
                int rMaskIndex = 2;
                int rDataStart = 0;
                //b[0] is always text in my case so no need to check;
                byte data = b[1];
                byte op = (byte) 127;
                rLength = (byte) (data & op);

                if(rLength==(byte)126) rMaskIndex=4;
                if(rLength==(byte)127) rMaskIndex=10;

                byte[] masks = new byte[4];

                int j=0;
                int i=0;
                for(i=rMaskIndex;i<(rMaskIndex+4);i++){
                    masks[j] = b[i];
                    j++;
                }

                rDataStart = rMaskIndex + 4;

                int messLen = len - rDataStart;

                byte[] message = new byte[messLen];

                for(i=rDataStart, j=0; i<len; i++, j++){
                    message[j] = (byte) (b[i] ^ masks[j % 4]);
                }

                System.out.println(new String(message)); 

                b = new byte[1024];

            }
        }
    }


    public static byte[] encode(String mess) throws IOException{
        byte[] rawData = mess.getBytes();

        int frameCount  = 0;
        byte[] frame = new byte[10];

        frame[0] = (byte) 129;

        if(rawData.length <= 125){
            frame[1] = (byte) rawData.length;
            frameCount = 2;
        }else if(rawData.length >= 126 && rawData.length <= 65535){
            frame[1] = (byte) 126;
            int len = rawData.length;
            frame[2] = (byte)((len >> 8 ) & (byte)255);
            frame[3] = (byte)(len & (byte)255); 
            frameCount = 4;
        }else{
            frame[1] = (byte) 127;
            int len = rawData.length;
            frame[2] = (byte)((len >> 56 ) & (byte)255);
            frame[3] = (byte)((len >> 48 ) & (byte)255);
            frame[4] = (byte)((len >> 40 ) & (byte)255);
            frame[5] = (byte)((len >> 32 ) & (byte)255);
            frame[6] = (byte)((len >> 24 ) & (byte)255);
            frame[7] = (byte)((len >> 16 ) & (byte)255);
            frame[8] = (byte)((len >> 8 ) & (byte)255);
            frame[9] = (byte)(len & (byte)255);
            frameCount = 10;
        }

        int bLength = frameCount + rawData.length;

        byte[] reply = new byte[bLength];

        int bLim = 0;
        for(int i=0; i<frameCount;i++){
            reply[bLim] = frame[i];
            bLim++;
        }
        for(int i=0; i<rawData.length;i++){
            reply[bLim] = rawData[i];
            bLim++;
        }

        return reply;
    }

    private static void doHandShakeToInitializeWebSocketConnection(InputStream inputStream, OutputStream outputStream) throws UnsupportedEncodingException {
        String data = new Scanner(inputStream,"UTF-8").useDelimiter("\\r\\n\\r\\n").next();

        Matcher get = Pattern.compile("^GET").matcher(data);

        if (get.find()) {
            Matcher match = Pattern.compile("Sec-WebSocket-Key: (.*)").matcher(data);
            match.find();                 

            byte[] response = null;
            try {
                response = ("HTTP/1.1 101 Switching Protocols\r\n"
                        + "Connection: Upgrade\r\n"
                        + "Upgrade: websocket\r\n"
                        + "Sec-WebSocket-Accept: "
                        + DatatypeConverter.printBase64Binary(
                                MessageDigest
                                .getInstance("SHA-1")
                                .digest((match.group(1) + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
                                        .getBytes("UTF-8")))
                        + "\r\n\r\n")
                        .getBytes("UTF-8");
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            try {
                outputStream.write(response, 0, response.length);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        } else {

        }
    }
}

pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>TreezHttpServer</groupId>
  <artifactId>TreezHttpServer</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <build>
    <sourceDirectory>src</sourceDirectory>
    <resources>
      <resource>
        <directory>src</directory>
        <excludes>
          <exclude>**/*.java</exclude>
        </excludes>
      </resource>
    </resources>
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.8.0</version>
        <configuration>
          <release>11</release>
        </configuration>
      </plugin>
    </plugins>    

  </build>

  <dependencies>

    <dependency>
        <groupId>javax.xml.bind</groupId>
        <artifactId>jaxb-api</artifactId>
        <version>2.2.11</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-core</artifactId>
        <version>2.2.11</version>
    </dependency>
    <dependency>
        <groupId>com.sun.xml.bind</groupId>
        <artifactId>jaxb-impl</artifactId>
        <version>2.2.11</version>
    </dependency>
    <dependency>
        <groupId>javax.activation</groupId>
        <artifactId>activation</artifactId>
        <version>1.1.1</version>
    </dependency>

  </dependencies>
</project>

JavaScript Client:

<!DOCTYPE html>

<html>

<head>

<meta charset="UTF-8">

<title>WebSocket Client</title>

 <script type="text/javascript">

      var wsocket;      

      function connect() {         

          wsocket = new WebSocket("ws://localhost:8000");          
          wsocket.onopen = onopen;
          wsocket.onmessage = onmessage;
          wsocket.onclose = onclose; 
      }

      function onopen() {
          console.log("Connected!");             
          wsocket.send('hello from client');
      }

      function onmessage(event) { 
         console.log("Data received: " + event.data); 
      }

      function onclose(e) {
         console.log("Connection closed.");              
      }

      window.addEventListener("load", connect, false);

  </script>

</head>

<body>
</body>

</html>

推荐