websocket的理解,写一个在线聊天室

对websocket的理解

websocket,也是应用层的网络通信协议,要理解它是什么,就要问为什么会出现这个协议

在没有websocket以前,我们都是用http协议做数据收发,渐渐的,我们发现有一些场景http的特性无法很好地处理。例如,服务端想主动发送给客户端信息的时候怎么办?如果用http来处理这个场景,就涉及到客户端方面的轮询。

但是轮询的逻辑是按照一定的频率,客户端不断地发送请求包,去看服务端是否"有话对我们说"。

这带来了两个主要的问题:

第一,服务端何时发送数据是不确定的,长时间持续地发送请求查询,其中大量的请求是无效的,网络利用率低下。

第二,对于需要实时发送的信息,轮询只能周期性地获取,如果服务端想要发送信息,需要等到下一个轮询周期才可以,会造成信息的延迟。如果是在线游戏,视频聊天什么的,用户当天就会打个差评再卸载掉。

所以,关键是要做到当服务端想发送的时候,就立刻主动地发送信息。

而websocket就能达成这一功能,它的特性是全双工通信 ,此外还有低延迟,数据包传输效率高的特性。这些特性都是相较于http协议来说的,你可以这么认为,想要专门应对需要高效全双工交互的应用场景,但http表示臣妾做不到啊,所以你新纳一个嫔妃websocket,专门帮你干这些活儿。

如果之前除了http协议以外没有接触过应用层协议,那么一开始是难以接受websocket概念的。为了更好地理解,需要跟http做一些关键的对比。

  1. http是请求-响应模式,必须要有请求,才有回复(且服务端不能主动请求)。websocket是全双工通信的,有信息就主动传达给对方。
  2. http短连接(一次来回后就默认关闭连接)。websocket是长连接。
  3. http是无状态。websocket是有状态的。

websocket是如何工作的

  1. 发出连接请求,客户端发送的第一个请求,是一个http请求,与普通http不同的是
arduino 复制代码
Upgrade: websocket  // upgrade是一个http标准头部,指定希望升级到的协议
Connection: Upgrade // connection设定完成协议升级后是否保持连接
  1. 服务器同意握手的响应
arduino 复制代码
Upgrade: websocket          // 确认升级到 WebSocket
Connection: Upgrade         // 核心:确认连接已升级
  1. 通信阶段

核心报文数据:

  • FIN:是否是结束帧,FIN=0表示还有后续,FIN=1表示是最后一个数据帧
  • Opcode:帧类型,数据类型(即这个数据包是干什么的)
  • Mask,是否掩码,1表示是掩码,掩码是将数据报文内容转换,而非是加密
  1. 连接关闭

一端发送关闭帧,另一端接受到关闭帧后,发送响应关闭帧。对话之后TCP断连。

代码实现一下websocket

现在通过java的方式来写一个websocket案例。

纯websocket的实现:

javascript 复制代码
<--依赖包-->
<dependency>
    <groupId>org.java-websocket</groupId>
    <artifactId>Java-WebSocket</artifactId>
    <version>1.5.4</version> 
</dependency>
typescript 复制代码
public class WebsocketChatRoom extends WebSocketServer {

    public WebsocketChatRoom(int port) {
        super(new InetSocketAddress(port));
    }


    @Override
    public void onOpen(WebSocket webSocket, ClientHandshake clientHandshake) {
        System.out.println("新连接到达:"+ webSocket.getRemoteSocketAddress());
    }

    @Override
    public void onClose(WebSocket webSocket, int i, String s, boolean b) {
        System.out.println("连接关闭:" + webSocket.getRemoteSocketAddress());
    }

    @Override
    public void onMessage(WebSocket webSocket, String s) {
        System.out.println("收到信息:" + s);
        // websocketServer自带的广播实现
        broadcast(s);
    }

    @Override
    public void onError(WebSocket webSocket, Exception e) {
        System.out.println("连接错误: "+e.getMessage());
    }

    @Override
    public void onStart() {

    }

    public static void main(String[] args) {
        int port = 8888;
        WebsocketChatRoom server = new WebsocketChatRoom(port);
        server.start();
        System.out.println("聊天室,启动!: " + port);
    }
}

上述的重点是继承WebSocketServer,它定义多个接口,每个接口望文生义,即各自连接阶段做的事情。最重要的是onMessage,参数为连接信息和报文文本。

作为后端开发,我们再请出deepseek大神帮我们写一个前端聊天窗口。

重要的是前端连接逻辑:

ini 复制代码
// 创建连接
socket = new WebSocket(serverUrl);

// websocket各阶段的处理器
socket.onopen = (event) => {
    console.log('WebSocket connection opened:', event);
    statusIndicator.className = 'status-indicator connected';
    statusText.textContent = 'Connected to server';
    sendButton.disabled = false;
    
    // Add connection message to chat
    addMessage('System', 'Connected to the WebSocket server', 'received');
};

socket.onmessage = (event) => {
    console.log('Message from server:', event.data);
    
    addMessage('Server', event.data, 'received');
    
    // Auto-scroll to bottom
    chatBox.scrollTop = chatBox.scrollHeight;
};

socket.onclose = (event) => {
    console.log('WebSocket connection closed:', event);
    statusIndicator.className = 'status-indicator';
    statusText.textContent = 'Disconnected from server';
    sendButton.disabled = true;
    
    // Add disconnection message to chat
    addMessage('System', 'Disconnected from the server', 'received');
    
    // Try to reconnect after 5 seconds
    setTimeout(() => {
        if (!socket || socket.readyState === WebSocket.CLOSED) {
            statusText.textContent = 'Reconnecting...';
            initWebSocket();
        }
    }, 5000);
};

socket.onerror = (error) => {
    console.error('WebSocket error:', error);
    statusText.textContent = 'Connection error';
    sendButton.disabled = true;
};

打开两个窗口,打开时会创建自己的用户名,然后在聊天室发送信息,即可同步信息了。

相关推荐
阿萨德528号5 小时前
Spring Boot + WebSocket超简单实战源码(前后端实时交互)
spring boot·websocket·交互
CryptoRzz21 小时前
印度尼西亚(IDX)股票数据对接开发
java·后端·websocket·web3·区块链
mudtools1 天前
飞书 .NET SDK 事件处理的幂等性与去重机制
websocket·.net·飞书·webhook
weixin79893765432...1 天前
深入浅出 WebSocket 协议
websocket·http·socket·sse
callJJ1 天前
WebSocket 两种实现方式对比与入门
java·python·websocket·网络协议·stomp
今晚务必早点睡2 天前
系统通信方式实战详解:HTTP、RPC、MQ、WebSocket 各用在什么场景?(附 SDK 示例)
websocket·http·rpc
*才华有限公司*2 天前
RTSP视频流播放系统
java·git·websocket·网络协议·信息与通信
栗子叶2 天前
网页接收服务端消息的几种方式
前端·websocket·http·通信
栗子叶2 天前
SSE、长轮询与 WebSocket 连接资源对比及 Spring Boot 配置指南
spring boot·websocket·网络协议