什么是WebSocket?
WebSocket用于在Web浏览器和服务器之间进行任意的双向数据传输的一种技术。WebSocket是一种在单个TCP连接上进行全双工通信的协议,使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
为什么要使用WebScoket?
随着互联网的发展,传统的HTTP协议已经很难满足应用日益复杂的需求。随着HTML5的诞生,WebSocket协议被提出,才实现浏览器于服务器的全双工通信,扩展了浏览器与服务端的通信,传统的HTTP协议是无状态的,每次请求(request)都要由客户端主动发起,服务器端处理后返回(reponse)结果,对于涉及涉及即时通信及实时数据,订阅推送等功能的应用带来了不小的麻烦,WebSocket协议提出之前,开发人员要实现这些实时性较强的功能,常会使用折衷的解决方法:轮询 和 Coment技术**,Coment本质上也是一种轮询,在轮询的基础上有所改进。
1、轮询
客户端以一定的时间间隔向服务端发出请求,以频繁请求的方式来保持客户端和服务器端的同步。
这种同步方案的最大问题是,当客户端以固定频率向服务器发起请求的时候,服务器端的数据可能并没有更新,这样会带来很多无谓的网络传输,所以这是一种非常低效的实时方案。
2、Coment-长轮询
是对定时轮询的改进和提高,目地是为了降低无效的网络传输。
服务器没有数据更新是,进行连接的保持,知道数据的更新或状态改变及时间过期。
通过这种机制来减少无效的客户端和服务器间的交互。
3、Coment-流
通常就是在客户端的页面使用一个隐藏的窗口向服务端发出一个长连接的请求。
服务器端接到这个请求后作出回应并不断更新连接状态以保证客户端和服务器端的连接不过期。
通过这种机制可以将服务器端的信息源源不断地推向客户端。
4、WebSocket 的到来
在目前以上的几种方案可以说并没有真正意义上的实时技术,都只是利用AJAX的方式来模拟实时连接效果。每一次请求、应答,都浪费了一定流量在相同的头部信息上,并且开发复杂度也较大。
伴随着HTML5推出的WebSocket,真正实现了Web的实时通信,使B/S模式具备了C/S模式的实时通信能力。
WebSocket的工作流程:
- 浏览器通过JavaScript向服务端发出建立WebSocket连接的请求
- 客户端与服务器端连接建立成功后
- 客户端和服务端就可以通过 TCP连接传输数据
因为WebSocket连接本质上是TCP连接,不需要每次传输都带上重复的头部数据,所以它的数据传输量比轮询和Comet技术小 了很多,同时能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。**
当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
利用JavaScript中API 用于创建 WebSocket 对象。
var Socket = new WebSocket(url, [protocol] );
以上代码中的第一个参数 url, 指定连接的 URL。第二个参数 protocol 是可选的,指定了可接受的子协议。
1、WebSocket 事件
以下是 WebSocket 对象的相关事件。假定我们创建了 Socket 对象:
事件 | 事件处理程序 | 描述 |
---|---|---|
open | Socket.onopen | 连接建立时触发 |
message | Socket.onmessage | 客户端接收服务端数据时触发 |
error | Socket.onerror | 通信发生错误时触发 |
close | Socket.onclose | 连接关闭时触发 |
2、WebSocket 方法
以下是 WebSocket 对象的相关方法。假定我们使用了创建了 Socket 对象:
方法 | 描述 |
---|---|
Socket.send() | 使用连接发送数据 |
Socket.close() | 关闭连接 |
接下来我们将会利用WebSocket对象的相关事件及相关方法实现一个简单的即时通讯效果。
WebSocket 实战
1、目录结构
2、导入WebSocket依赖
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.4.0</version>
</dependency>
3、编写服务器端
import org.java_websocket.WebSocket;
import org.java_websocket.handshake.ClientHandshake;
import org.java_websocket.server.WebSocketServer;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
/**
* @Author 21171326@qq.com
* @Create 2021/11/23 14:03
**/
public class ServerDemo extends WebSocketServer {
public ServerDemo(int port) throws UnknownHostException {
super(new InetSocketAddress(port));
System.out.println("websocket Server start at port:"+port);
}
/**
* 触发连接事件
*/
@Override
public void onOpen(WebSocket conn, ClientHandshake clientHandshake) {
System.out.println("新连接:" + conn.getRemoteSocketAddress().getAddress().getHostAddress());
}
/**
*
* 连接断开时触发关闭事件
*/
@Override
public void onClose(WebSocket conn, int code, String reason, boolean remote) {
}
/**
* 客户端发送消息到服务器时触发事件
*/
@Override
public void onMessage(WebSocket conn, String message) {
System.out.println("客户端发送消息内容: "+ message);
//向客户端发送消息
conn.send(message);
}
/**
* 触发异常事件
*/
@Override
public void onError(WebSocket conn, Exception e) {
//e.printStackTrace();
if( conn != null ) {
//some errors like port binding failed may not be assignable to a specific websocket
}
}
@Override
public void onStart() {
}
/**
* 启动服务端
* @param args
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException {
new ServerDemo(8888).start();
}
}
4、前端页面编写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSocket-Test</title>
</head>
<body>
<button onclick="send()">发送请求</button>
<p id="status"></p>
</body>
<script type="text/javascript">
let websocket = null;
//判断浏览器是否支持WebSocket
if (!window.WebSocket) {
alert('该浏览器不支持WebSocket');
} else {
websocket = new WebSocket("ws://localhost:8888/"); //连接WebSocket
}
//连接发生错误的回调方法
websocket.onerror = function() {
setMessageInnerHTML("WebSocket连接发生错误");
};
//连接成功建立的回调方法
websocket.onopen = function() {
console.log("连接成功");
}
//发送信息
send = () => {
console.log("发送信息");
websocket.send('WebSocket');
}
//接收到消息的回调方法
websocket.onmessage = function(event) {
console.log(event.data);
}
//连接关闭的回调方法
websocket.onclose = function() {
setMessageInnerHTML("WebSocket连接关闭");
}
//关闭WebSocket连接
function closeWebSocket() {
websocket.close();
}
</script>
</html>
5、测试结果
联想一下简单的推送啥的就都可以做了。但用户以及用户之间的即时交流和群发信息还得继续摸索。