1. WebSocket概述
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
1.1.为什么需要WebScoket?
客户端(一般是Web浏览器)向服务器提交HTTP请求,而我们知道HTTP是无状态的,也就是说,它将每个请求当成唯一和独立的。无状态协议具有一些优势,例如,服务器不需要保存有关会话的信息,从而不需要存储数据。但是,这也意味着在每次HTTP请求和响应中都会发送关于请求的冗余信息。
从根本上讲,HTTP还是半双工的协议,也就是说,在同一时刻流量只能单向流动:客户端向服务器发送请求(单向),然后服务器响应请求(单向)。
1.2 WebSocket介绍
我们知道,服务器一般是等待用户发送请求过来,然后将资源响应过去。服务器是无法主动去发送请求给客户端的。
在WebSocket未出来之前,实时Web应用程序的尝试多半围绕“轮询”(polling)技术进行,就是不断的去访问服务器,是否有新数据到来。
当采用了WebSocket的时候,浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
故建议前端后端都需要了解,本人学习WebSocket的需求是出于有一个即时通讯的小项目需要去做;
2. Server
参考链接
逻辑理解为 由Server进行查找在线用户,进行消息转发;
<dependencies>
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
3. JavaClient
这里存在一个问题,Java程序客户端无法保持WebSocket的长链接。
public class MyWebSocketClient extends WebSocketClient {
public MyWebSocketClient(String url) throws URISyntaxException {
super(new URI(url));
}
@Override
public void onOpen(ServerHandshake shake) {
System.out.println("握手...");
for (Iterator<String> it = shake.iterateHttpFields(); it.hasNext(); ) {
String key = it.next();
System.out.println(key + ":" + shake.getFieldValue(key));
}
}
@Override
public void onMessage(String paramString) {
System.out.println("接收到消息:" + paramString);
}
@Override
public void onClose(int paramInt, String paramString, boolean paramBoolean) {
System.out.println("关闭...");
}
@Override
public void onError(Exception e) {
System.out.println("异常" + e);
}
}
测试用例:
@Test
public void testclient10() {
try {
MyWebSocketClient client = new MyWebSocketClient("ws://127.0.0.1:8081/imserver/10");
client.connect();
while (!client.getReadyState().equals(WebSocket.READYSTATE.OPEN)) {
System.out.println("还没有打开");
}
System.out.println("建立websocket连接");
JSONObject jsonObject = new JSONObject();
jsonObject.put("toUserId", "20");
jsonObject.put("message", "okokok");
client.send(jsonObject.toJSONString());
client.close();
} catch (URISyntaxException e) {
e.printStackTrace();
}
}
@Test
public void testclient20() {
try {
MyWebSocketClient client = new MyWebSocketClient("ws://127.0.0.1:8081/imserver/20");
client.connect();
while (!client.getReadyState().equals(WebSocket.READYSTATE.OPEN)) {
System.out.println("还没有打开");
}
System.out.println("建立websocket连接");
} catch (URISyntaxException e) {
e.printStackTrace();
}
}