# **WebSocket 服務端**
WebSocket 在服務端的實現非常豐富。Node.js、Java、C++、Python 等多種語言都有自己的解決方案。
以下,介紹我在學習 WebSocket 過程中接觸過的 WebSocket 服務端解決方案。
## **Node.js**
常用的 Node 實現有以下三種。
- μWebSockets
- Socket.IO
- WebSocket-Node
## **Java**
Java 的 web 一般都依托于 servlet 容器。
我使用過的 servlet 容器有:Tomcat、Jetty、Resin。其中Tomcat7、Jetty7及以上版本均開始支持 WebSocket(推薦較新的版本,因為隨著版本的更迭,對 WebSocket 的支持可能有變更)。
此外,Spring 框架對 WebSocket 也提供了支持。
雖然,以上應用對于 WebSocket 都有各自的實現。但是,它們都遵循RFC6455 的通信標準,并且 Java API 統一遵循 JSR 356 - JavaTM API for WebSocket 規范。所以,在實際編碼中,API 差異不大。
### **Spring**
Spring 對于 WebSocket 的支持基于下面的 jar 包:
```
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-websocket</artifactId>
<version>${spring.version}</version>
</dependency>
```
在 Spring 實現 WebSocket 服務器大概分為以下幾步:
#### **創建 WebSocket 處理器**
擴展 TextWebSocketHandler 或 BinaryWebSocketHandler ,你可以覆寫指定的方法。Spring 在收到 WebSocket 事件時,會自動調用事件對應的方法。
```
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.TextMessage;
public class MyHandler extends TextWebSocketHandler {
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
// ...
}
}
```
WebSocketHandler 源碼如下,這意味著你的處理器大概可以處理哪些 WebSocket 事件:
```
public interface WebSocketHandler {
/**
* 建立連接后觸發的回調
*/
void afterConnectionEstablished(WebSocketSession session) throws Exception;
/**
* 收到消息時觸發的回調
*/
void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception;
/**
* 傳輸消息出錯時觸發的回調
*/
void handleTransportError(WebSocketSession session, Throwable exception) throws Exception;
/**
* 斷開連接后觸發的回調
*/
void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception;
/**
* 是否處理分片消息
*/
boolean supportsPartialMessages();
}
```
#### **配置 WebSocket**
配置有兩種方式:注解和 xml 。其作用就是將 WebSocket 處理器添加到注冊中心。
實現 WebSocketConfigurer
```
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myHandler(), "/myHandler");
}
@Bean
public WebSocketHandler myHandler() {
return new MyHandler();
}
}
```
xml 方式
```
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:websocket="http://www.springframework.org/schema/websocket"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/websocket
http://www.springframework.org/schema/websocket/spring-websocket.xsd">
<websocket:handlers>
<websocket:mapping path="/myHandler" handler="myHandler"/>
</websocket:handlers>
<bean id="myHandler" class="org.springframework.samples.MyHandler"/>
</beans>
```
`更多配置細節可以參考:Spring WebSocket 文檔`
javax.websocket
如果不想使用 Spring 框架的 WebSocket API,你也可以選擇基本的 javax.websocket。
首先,需要引入 API jar 包。
<!-- To write basic javax.websocket against -->
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.0</version>
</dependency>
如果使用嵌入式 jetty,你還需要引入它的實現包:
<!-- To run javax.websocket in embedded server -->
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-server-impl</artifactId>
<version>${jetty-version}</version>
</dependency>
<!-- To run javax.websocket client -->
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>javax-websocket-client-impl</artifactId>
<version>${jetty-version}</version>
</dependency>
@ServerEndpoint
這個注解用來標記一個類是 WebSocket 的處理器。
然后,你可以在這個類中使用下面的注解來表明所修飾的方法是觸發事件的回調
// 收到消息觸發事件
@OnMessage
public void onMessage(String message, Session session) throws IOException, InterruptedException {
...
}
// 打開連接觸發事件
@OnOpen
public void onOpen(Session session, EndpointConfig config, @PathParam("id") String id) {
...
}
// 關閉連接觸發事件
@OnClose
public void onClose(Session session, CloseReason closeReason) {
...
}
// 傳輸消息錯誤觸發事件
@OnError
public void onError(Throwable error) {
...
}
ServerEndpointConfig.Configurator
編寫完處理器,你需要擴展 ServerEndpointConfig.Configurator 類完成配置:
public class WebSocketServerConfigurator extends ServerEndpointConfig.Configurator {
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
sec.getUserProperties().put(HttpSession.class.getName(), httpSession);
}
}
然后就沒有然后了,就是這么簡單。