如何在Java中实现WebSocket服务器?

8

我正在为通讯应用程序设置第一个WebSocket服务器。 我似乎无法弄清楚Java中的WebSocket是如何实现的。

我尝试过使用基于注释的Endpoint进行创建,但并没有成功。我不确定客户端信息将通过哪里传递。这基本上就是我的代码要点,没有涉及到令人沉闷的细节。

我正在尝试让MessageHelper类处理WebSocket信息传输,但我不知道该如何实际传输数据。

class MainServer implements Runnable {
// VARIABLES
    ServerSocket serverSocket = null;
    int port;
// CONSTRUCTORS
    MainServer(int p) {
        this.port = p;
    }
// METHODS
    public void run() {
        openServerSocket();
        while(!isStopped()){
            try{
                clientSocket = serverSocket.accept();
            } catch(IOException e) {
                // Do something
            }
            new Thread(new MainThread(clientSocket)).start();
        }
    }
}

// Other methods below.

public class MainThread {

    final Socket socket;


    MainThread(Socket s) {
        this.socket = s;
    }

    public void run() {
        try{
            BufferedReader br = new BufferedReader(
                new InputStreamReader(socket.getInputStream()));

            String input = br.readLine(), read = br.readLine();
            while(!input.isEmpty()) {
                read += "\n";
                read += input;
                input = br.readLine();
            }

            /**
            *  Everything works fine, I'm just not sure where to go
            * from here. I tried creating MessageHelper into the java
            * websocket implementation using annotations but it did not 
            * accept input from the client after the handshake was
            * made. My client would send something but it would just 
            * give and EOFException.
            **/
            if(websocketHandshakeRequest(read)) {
                MessageHelper messageHelper = 
                    new MessageHelper(this.socket);
            } else {
                // Do something
            }
        } catch(Exception e) {
            // Do something.
        }
    }
}
2个回答

17
不要被WebSocket的名称所迷惑。TCP套接字和WebSocket是完全不同类型的“套接字”。
在Java中,您使用ServerSocket进行TCP套接字。TCP是一种传输层协议,用于实现应用层协议,如POP3和HTTP。
WebSocket是一个HTTP / 1.1协议升级,通常用于Web服务器和Web浏览器。您不能使用ServerSocket来处理WebSocket协议,至少不像您认为的那样直截了当。首先,您必须实现HTTP / 1.1协议,然后在其上实现WebSocket协议。
在Java世界中,您可以使用Web服务器,例如Tomcat或Jetty,它们提供WebSocket实现和高级Java API。此API是Jave企业版(JEE)的一部分。另请参见Jave EE 7教程-第18章Java API for WebSocket
例如,Jetty是一款轻量级的JEE Web服务器,可嵌入应用程序中或作为独立服务器运行。请参阅Jetty开发指南-第26章WebSocket介绍
因此,在WebSocket启用的JEE Web服务器(例如Jetty)中运行的Java Web应用程序中,您可以按以下方式实现服务器端WebSocket:
package com.example.websocket;

import org.apache.log4j.Logger;

import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;

@ServerEndpoint("/toUpper")
public class ToUpperWebsocket {

  private static final Logger LOGGER = Logger.getLogger(ToUpperWebsocket.class);

  @OnOpen
  public void onOpen(Session session) {
    LOGGER.debug(String.format("WebSocket opened: %s", session.getId()));
  }

  @OnMessage
  public void onMessage(String txt, Session session) throws IOException {
    LOGGER.debug(String.format("Message received: %s", txt));
    session.getBasicRemote().sendText(txt.toUpperCase());
  }

  @OnClose
  public void onClose(CloseReason reason, Session session) {
    LOGGER.debug(String.format("Closing a WebSocket (%s) due to %s", session.getId(), reason.getReasonPhrase()));
  }

  @OnError
  public void onError(Session session, Throwable t) {
    LOGGER.error(String.format("Error in WebSocket session %s%n", session == null ? "null" : session.getId()), t);
  }
}

你可以使用@ServerEndpoint注释将你的类注册为特定路径的WebSocket处理程序。你的WebSocket URL是ws://host:port/context/toUpper或者在HTTPS连接中是wss://host:port/context/toUpper编辑: 这里有一个非常简单的HTML页面,用于演示与上述WebSocket的客户端连接。该页面由与WebSocket相同的Web服务器提供服务。包含WebSocket的Web应用程序部署在本地主机端口7777的上下文"websocket"中。
    <html>
    <body>
    <h2>WebSocket Test</h2>
    <div>
    <input type="text" id="input" />
    </div>
    <div>
    <input type="button" id="connectBtn" value="CONNECT" onclick="connect()" />
    <input type="button" id="sendBtn" value="SEND" onclick="send()" disable="true" />
    </div>
    <div id="output">
    <h2>Output</h2>
    </div>
    </body>
    <script type="text/javascript">
    var webSocket;
    var output = document.getElementById("output");
    var connectBtn = document.getElementById("connectBtn");
    var sendBtn = document.getElementById("sendBtn");
    var wsUrl = (location.protocol == "https:" ? "wss://" : "ws://") + location.hostname + (location.port ? ':'+location.port: '') + "/websocket/toUpper";

    function connect() {
      // open the connection if one does not exist
      if (webSocket !== undefined
        && webSocket.readyState !== WebSocket.CLOSED) {
        return;
      }

      updateOutput("Trying to establish a WebSocket connection to <code>" + wsUrl + "</code>");

      // Create a websocket
      webSocket = new WebSocket(wsUrl);

      webSocket.onopen = function(event) {
        updateOutput("Connected!");
        connectBtn.disabled = true;
        sendBtn.disabled = false;
      };

      webSocket.onmessage = function(event) {
        updateOutput(event.data);
      };

      webSocket.onclose = function(event) {
        updateOutput("Connection Closed");
        connectBtn.disabled = false;
        sendBtn.disabled = true;
      };
    }

    function send() {
      var text = document.getElementById("input").value;
      webSocket.send(text);
    }

    function closeSocket() {
      webSocket.close();
    }

    function updateOutput(text) {
      output.innerHTML += "<br/>" + text;
    }
    </script>
    </html>

Sample WebSocket webpage rendered in Firefox


好的,我已经阅读了你发送的链接,但我仍然不确定客户端如何访问ToUpperWebsocket类。 - Kyler
@Kyler:我更新了我的答案,并包含了一些客户端代码。 - vanje
我已经使用ServerSocket构建了一个WebSocket服务器来监听端口,使用Socket处理WebSocket协议。到目前为止,一切都很好,从客户端到服务器解码消息并回复的时间为4-12毫秒,支持Ping/Pong帧和Close帧,也许还有其他部分我没有涉及。我本来不是计算机科学专业的,所以在TCP和UDP方面缺乏知识,你的意思是WebSocket在“握手”之后不运行在TCP上,因此ServerSocket不是正确的类吗? - Jason Rich Darmawan
有趣的答案。那为什么编译器说有错误呢? - vincent thorpe
1
@vincent thorpe:也许是类路径中缺少了websocket JAR文件?如果没有更多的信息,我们无法帮助您解决具体的错误。您应该考虑创建一个新的问题来寻求帮助。 - vanje
显示剩余3条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接