前言
欢迎来到WebSocket入门案例系列的第一天!在今天的博客中,我们将一起探索WebSocket的基础知识和使用方法。本系列将以一个简单的入门案例为基础,带领您逐步了解WebSocket的原理和用法。
一、什么是 WebSocket ?
WebSocket是一种在Web应用程序中实现实时双向通信的协议。它提供了一种持久连接,允许服务器主动向客户端推送数据,而不需要客户端发起请求。
传统的Web应用程序使用HTTP协议进行通信,这种通信方式是基于请求-响应模式的。客户端发送请求给服务器,服务器响应请求并返回相应的数据。但是这种方式存在一些限制,特别是对于实时性要求较高的应用场景,如聊天室、股票行情等。
WebSocket通过引入新的协议,提供了一种更高效、更低延迟的通信方式。相对于HTTP,WebSocket具有以下特点:
-
双向通信:WebSocket允许客户端和服务器之间进行双向通信,服务器可以主动向客户端推送数据,而不仅仅是响应客户端的请求。这使得实时性要求较高的应用程序能够更加高效地进行数据传输。
-
持久连接:WebSocket在建立连接后,保持持久的连接状态,而不需要每次通信都重新建立连接。这消除了每次请求建立连接和断开连接的开销,减少了网络流量和延迟。
-
低开销:相对于传统的HTTP请求-响应模式,WebSocket协议的数据帧头部较小,有效减少了通信过程中的数据开销。此外,由于使用持久连接,减少了连接建立和断开的开销。
-
兼容性:WebSocket协议基于TCP协议,通过HTTP/HTTPS进行握手协商,并在握手成功后升级为WebSocket连接。由于握手过程使用标准的HTTP/HTTPS协议,因此WebSocket可以通过大多数防火墙和代理服务器。
WebSocket在现代Web应用程序中被广泛应用,特别是对于需要实时通信和即时更新的应用场景。它为开发者提供了一种更加便捷、高效的方式来构建实时性强的Web应用程序。无论是聊天应用、实时博客评论、多人协作工具还是股票行情等都可以借助WebSocket实现更好的用户体验和数据交互。
二、为什么要使用 WebSocket
WebSocket作为一种实现实时双向通信的协议,具有以下优点,这也是为什么要使用WebSocket的原因:
-
实时双向通信:传统的Web应用程序都是基于HTTP协议进行请求和响应的,无法实现实时双向通信。而WebSocket协议可以在客户端和服务器之间建立持久连接,实现实时双向通信,从而满足实时性比较强的应用场景。
-
低延迟:与HTTP协议相比,WebSocket协议的数据帧头部较小,有效减少了通信过程中的数据开销。由于使用持久连接,减少了连接建立和断开的开销,降低了延迟,提高了应用程序的响应速度和用户体验。
-
更好的扩展性:WebSocket协议采用标准的TCP协议,通过HTTP/HTTPS进行握手协商,并在握手成功后升级为WebSocket连接。由于握手过程使用标准的HTTP/HTTPS协议,WebSocket可以通过大多数防火墙和代理服务器。这使得应用程序更容易部署和扩展。
-
更低的网络流量:由于WebSocket协议使用二进制帧传输数据,相对于HTTP协议使用文本格式传输数据,WebSocket可以减少网络流量,提高应用程序的效率和性能。
总之,WebSocket协议提供了一种更高效、更低延迟、更实时、更灵活的通信方式,使得实时性较强的应用场景(如聊天室、在线游戏、多人协作工具等)更容易实现。如果您需要构建这些类型的应用程序,那么WebSocket将是您不错的选择。
三、实现一个单的 Hello WebSocket
1、新建项目,结构如下
2、导入依赖
<!-- websocket 依赖 -->
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
<version>1.1</version>
<scope>provided</scope>
</dependency>
<!-- 打印日志 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.8</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
下面是每个依赖项的作用:
javax.websocket-api:这是一个Java API,用于支持WebSocket通信协议。WebSocket允许在客户端和服务器之间进行双向通信,实时地发送消息和数据。这个依赖项提供了WebSocket的核心接口和类。
logback-classic:这是一个Java日志框架,用于在应用程序中记录和输出日志信息。logback-classic是logback框架的核心组件,它提供了强大的日志记录功能和灵活的配置选项。
lombok:这是一个Java库,通过注解自动化简化了Java代码的编写。使用lombok可以减少样板代码,例如自动生成getter、setter、构造函数等。它提供了一些注解来简化代码的编写和维护,提高开发效率。
3、 编写 controller 类
@ServerEndpoint("/connect")
@Slf4j
public class WebSocketServer {
/**
* 打开连接的方法,当有一个客户端连接服务端的时候
* 这个方法就会调用一次
*
* @OnOpen注解:表示连接
*
*/
@OnOpen
public void onOpen(){
log.info("客户端已连接" );
}
/**
* 客户端发送消息的方法
*/
@OnMessage
public void onMessage(String message,Session session) throws IOException {
log.info("消息:" + message);
// 向当前客户端发送一个消息
session.getBasicRemote().sendText(message);
}
/**
* 当客户端断开连接后调用此方法
*/
@OnClose
public void onClose(Session session){
log.info("客户端已断开连接");
}
}
在给出每个注解的用途之前,需要说明这段代码是Java中使用WebSocket的示例代码,使用了javax.websocket包提供的注解。
@ServerEndpoint("/connect"):
- 作用:将Java类标记为WebSocket服务器端点。
- 解释:这个注解用于标识一个类是WebSocket的服务器端点,指定了客户端连接的URL路径。在上述示例中,客户端需要通过连接至"/connect"路径来与该服务器端点进行通信。
@OnOpen:
- 作用:定义打开连接时调用的方法。
- 解释:当有客户端连接到WebSocket服务器端点时,被该注解标记的方法将会被调用。在示例中,onOpen()方法在客户端连接成功后执行,并打印出连接成功的消息。
@OnMessage:
- 作用:定义接收客户端消息时调用的方法。
- 解释:当WebSocket服务器端点接收到客户端发送的消息时,被该注解标记的方法将会被调用。在示例中,onMessage()方法接收两个参数:String类型的message表示接收到的消息内容,Session类型的session表示与该客户端的会话。该方法在接收到消息后,会将消息原样发送回客户端。
@OnClose:
- 作用:定义客户端断开连接时调用的方法。
- 解释:当与WebSocket服务器端点建立连接的客户端断开连接时,被该注解标记的方法将会被调用。在示例中,onClose()方法接收一个参数:Session类型的session,表示与断开连接的客户端的会话。该方法在客户端断开连接后执行,并打印出断开连接的消息。
这些注解是Java WebSocket API提供的一部分,通过使用这些注解,可以方便地定义WebSocket服务器端点的行为,包括连接建立、消息接收和断开连接等操作。
这个类是一个示例的WebSocket服务器端点类,用于处理客户端与服务器之间的WebSocket通信。主要功能如下:
打开连接:当有客户端连接到WebSocket服务器端点时,会调用
onOpen()
方法,并打印出连接成功的消息。接收消息:当WebSocket服务器端点接收到客户端发送的消息时,会调用
onMessage()
方法,并打印出接收到的消息。同时,该方法会将接收到的消息原样发送回客户端。断开连接:当与WebSocket服务器端点建立连接的客户端断开连接时,会调用
onClose()
方法,并打印出断开连接的消息。
这个类是使用了Java WebSocket API提供的注解来定义WebSocket服务器端点的行为。通过这些注解,可以方便地处理WebSocket的连接、消息接收和断开连接等操作。
4、编写一个 html 页面接收数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>websocket 客户端</h1>
<script>
// 构建 websocket 的实例,连接后台 server 的请求地址
// websocket 在第一次请求时使用 http 协议在连接服务器,告诉服务器
// 接下来要使用 websocket 进行通信,此时服务器将进行协议升级,会在
// http 的请求头中带有 upgrade:websocket 的头信息
var webSocket = new WebSocket("ws://localhost:8080/connect");
// onopen 方法
webSocket.onopen = function () {
// 发送一个消息
webSocket.send("hello websocket");
}
// onmessage 方法,接受服务端发送的信息
webSocket.onmessage = function (event) {
alert("服务器的消息:" + event.data);
}
// onclose 方法
webSocket.onclose = function () {
alert("已断开连接");
}
</script>
</body>
</html>
这段代码是一个简单的WebSocket客户端示例,用于与WebSocket服务器进行通信。它的作用是:
创建WebSocket实例:通过
var webSocket = new WebSocket("ws://localhost:8080/connect");
语句创建了一个WebSocket实例,并指定了连接的服务器地址。连接建立:当WebSocket连接成功建立时,会自动触发
onopen
事件处理函数,其中的webSocket.onopen
定义了连接建立时的操作。在示例中,onopen
函数中发送了一条消息webSocket.send("hello websocket");
到服务器。接收消息:当WebSocket客户端接收到来自服务器端的消息时,会触发
onmessage
事件处理函数,其中的webSocket.onmessage
定义了接收消息时的操作。在示例中,当接收到消息时,会通过弹窗的方式显示服务器端发送的消息。断开连接:当WebSocket连接关闭时,会触发
onclose
事件处理函数,其中的webSocket.onclose
定义了连接关闭时的操作。在示例中,当连接关闭时,会通过弹窗的方式提示连接已断开。
这段代码展示了一个最基本的WebSocket客户端的工作流程,包括连接建立、消息发送和接收、连接断开等操作。您可以将其用于与WebSocket服务器进行实时通信,实现双向数据传输的功能。根据具体需求,您可以根据这个示例进行定制和扩展,添加更多的业务逻辑和交互功能。
5、运行效果
我们在前端接收到了后台发送来的信息,在后台我们也接受到前端发送的信息,这就是一个简单的多对多的群聊了。
四、实现多人群聊
1、编写 controller
@ServerEndpoint("/connect")
@Slf4j
public class WebSocketServer {
/**
* 用户列表
*/
private static final List<Session> users = new ArrayList<>();
/**
* 打开连接的方法,当有一个客户端连接服务端的时候
* 这个方法就会调用一次
*
* @OnOpen注解:表示连接
*
* @param session 表示一个 websocket 客户端的连接会话
* 每一个客户端连接就会创建一个 session 会话
*/
@OnOpen
public void onOpen(Session session){
log.info("客户端已连接" );
// 将 session 添加到用户列表中
users.add(session);
}
/**
* 客户端发送消息的方法
*/
@OnMessage
public void onMessage(String message,Session session) throws IOException {
log.info("消息:" + message);
// 获取当前时间
String formattedTime = new SimpleDateFormat("HH:mm:ss").format(new Date());
// 向当前客户端发送一个消息,包含发送时间
String messageWithTime = "[" + formattedTime + "] " + message;
for (Session user : users) {
// 群发信息
user.getBasicRemote().sendText(messageWithTime);
}
}
/**
* 当客户端断开连接后调用此方法
*/
@OnClose
public void onClose(Session session){
log.info("客户端已断开连接");
// 用户离线
users.remove(session);
}
}
解释一下每一行代码的意思:
1)、定义了一个静态的会话列表users
,用于存储所有连接到WebSocket服务端的客户端Session
对象。
private static final List<Session> users = new ArrayList<>();
2)、使用@OnOpen
注解声明一个方法,该方法用于处理WebSocket客户端连接到服务器后的操作。当有一个新客户端连接到服务器时,该方法会被自动调用。在该方法中,首先记录下客户端连接成功的日志信息,然后将客户端的Session
对象保存到静态会话列表中。
@OnOpen
public void onOpen(Session session){
log.info("客户端已连接" );
// 将 session 添加到用户列表中
users.add(session);
}
3)、使用@OnMessage
注解声明一个方法,该方法用于处理WebSocket客户端发送消息的操作。当客户端向服务器发送消息时,该方法会被自动调用,并传入消息内容和对应的Session
对象。在该方法中,首先记录下客户端发送的消息内容,然后获取当前时间,并将时间和消息内容拼接为一个新的字符串。最后,遍历所有连接到服务器的客户端(即静态会话列表users
),并将消息广播给所有客户端。
@OnMessage
public void onMessage(String message,Session session) throws IOException {
log.info("消息:" + message);
// 向当前客户端发送一个消息
// session.getBasicRemote().sendText(message);
// 获取当前时间
String formattedTime = new SimpleDateFormat("HH:mm:ss").format(new Date());
// 向当前客户端发送一个消息,包含发送时间
String messageWithTime = "[" + formattedTime + "] " + message;
for (Session user : users) {
// 群发信息
user.getBasicRemote().sendText(messageWithTime);
}
}
4)使用@OnClose
注解声明一个方法,该方法用于处理WebSocket客户端断开连接的操作。当有一个客户端与服务器断开连接时,该方法会被自动调用,并传入断开连接的Session
对象。在该方法中,首先记录下客户端断开连接的日志信息,然后将与断开连接的客户端对应的Session
对象从静态会话列表中移除。
@OnClose
public void onClose(Session session){
log.info("客户端已断开连接");
// 用户离线
users.remove(session);
}
2、编写一个页面发送信息
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="js/JQuery文件.txt.js"></script>
</head>
<body>
<h1>聊天室</h1>
<div id="msg"></div>
<input id="message" type="text"/>
<input type="button" value="发送"/>
<script>
//创建websocket对象
let ws = new WebSocket("ws://localhost:8080/connect");
//接收服务端的消息
ws.onmessage = function(event){
let message = event.data;
//将消息放入聊天框
$('#msg').append(message + '<br>');
}
$(function(){
$(':button').on('click',function(){
//获取文本消息
let msg = $('#message').val();
//发送消息
ws.send(msg);
//清空发送框
$('#message').val('');
});
})
</script>
</body>
</html>
这段代码是一个简单的HTML页面,它实现了一个基本的聊天室功能。具体功能如下:
- 在页面上显示一个标题为"聊天室"的大标题。
- 有一个用于显示聊天消息的<div>元素,它的id属性为"msg"。
- 有一个<input>元素,用于输入要发送的消息,它的id属性为"message"。
- 有一个<input>按钮,用于发送消息,按钮上显示"发送"。
- 使用JavaScript和jQuery库来处理页面上的交互逻辑。
在脚本部分,代码实现了以下功能:
- 创建了一个WebSocket对象,通过指定WebSocket服务器的URL来建立与服务器的连接。在这个例子中,服务器的URL是"ws://localhost:8080/connect"。
- 设置了一个事件处理程序(ws.onmessage),当接收到来自服务器的消息时,会触发该事件,并将消息显示在聊天框中。
- 使用jQuery库,在页面加载完成后,绑定了按钮的点击事件处理程序。当按钮被点击时,获取输入框中的文本消息,并通过WebSocket发送给服务器。然后清空输入框,以便输入下一条消息。
通过将这段代码部署到一个能够处理WebSocket协议的服务器上,你可以创建一个简单的聊天室页面,用户可以在其中实时地发送和接收消息。当用户在输入框中输入消息并点击发送按钮时,消息将通过WebSocket发送给服务器,在服务器上处理后,会将消息广播给所有连接的客户端,以便显示在聊天框中。这样就实现了简单的聊天室功能。
3、运行效果
五、使用局域网 IP 地址实现多人群聊
1、使用命令查看 IP 地址
win + r 打开命令提示符,输入 cmd 回车进入。在控制面板输出 : ipconfig 回车即可查询到自己本机的 IP.
2、在 client.html 页面更改 url
只需要把 localhost 换成自己本机的 IP 地址即可。
3、运行效果
改完 url 地址后,我们在浏览器就不能使用 localhost:8080 去访问了。
使用 IP 地址后的访问路径为:http://本机IP地址:8080/chat.html
4、什么是局域网?
局域网通常用于连接位于同一地理位置的多台计算机和设备。
注意:我们使用的是局域网的 IP 地址去和同学聊天的,如果你们使用的是同一个网络就能够正常的访问这个路径去聊天,如果不在同一网络就不能。比如:教室、学校、家里的WIFI,都可以。
六、总结
本次案例,我们简单的讲解了实现聊天的功能。但是,这只是一个开头,我们要实现真正的聊天还有很多其他的功能要做,比如:登录,登录成功后获取用户的名称。我们这次聊天是不知道用户名的,只有时间和内容,那么在下一章节我将要讲解如何实现登录后实现聊天。
七、gitee 案例
地址:ch01 · qiuqiu/WebSocket-study - 码云 - 开源中国 (gitee.com)