加入星计划,您可以享受以下权益:

  • 创作内容快速变现
  • 行业影响力扩散
  • 作品版权保护
  • 300W+ 专业用户
  • 1.5W+ 优质创作者
  • 5000+ 长期合作伙伴
立即加入
  • 正文
    • Part 01●  WebSocket是什么? ●
    • Part 02●  Websocket报文 ●
    • Part 03●  代码实现 ●
    • Part 04●  结束语 ●
  • 推荐器件
  • 相关推荐
  • 电子产业图谱
申请入驻 产业图谱

五分钟技术趣谈 | 浅谈WebSocket协议在Web领域的应用

2023/12/08
3422
阅读需 14 分钟
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

作者:浦春城,单位:中国移动智慧家庭运营中心

WebSocket是一种双向通信协议,主要应用在Web浏览器,解决服务器端主动向浏览器推送消息的问题。WebSocket常见的应用场景有页游、视频网站、在线文档、股票网站等。

Part 01●  WebSocket是什么? 

WebSocket是一种在Web应用程序中提供双向通信的协议。它允许服务器主动向客户端推送数据,而不是像传统的HTTP请求-响应模式一样,客户端必须发送请求才能获取数据。WebSocket 最早是在HTML5中引入的,建立在HTTP协议之上,使用握手阶段来升级连接,然后通过保持连接的状态来实现实时通信。

与传统的HTTP协议相比,WebSocket具有以下优势:

⑴ 增强实时性

服务器可以随时主动给客户端下发数据,相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少。和传统的轮询比较,WebSocket也可以在短时间内更有效率地传递数据;

⑵ 维持连接状态

在一些需要身份认证的场景下,HTTP请求可能需要在每个请求都携带状态信息(服务器不记录每次的请求和响应信息),而WebSocket一次连接建立后就会保持住会话状态,这就使其成为一种有状态的协议,后续通信时就可以省略部分状态信息;

⑶ 更灵活的扩展支持

开发者可以对WebSocket自定义二进制帧,相对HTTP,可以更轻松地处理二进制内容,此外开发者也自行扩展协议、实现部分自定义的子协议;

⑷ 更好的压缩效果

WebSocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。

Part 02●  Websocket报文 

2.1 报文格式

- 第0个字节

0位(FIN):0表示报文没有结束,1表示报文结束。

1-3位(RSV1、RSV2、RSV3):保留字段,一般全部为0。也可用于扩展自己的协议。

4-7位(opcode):报文类型。0 代表一个继续帧,1代表文本帧,2代表二进制帧,8 代表连接关闭,9 代表ping,10代表pong。

- 第1个字节

8位(MASK):1表示需要掩码操作,0表示不需要。如果为1,数据帧的masking-key属性会存在一个值,接收方会利用这个值来进行解掩码操作,所有从客户端传输到服务器的数据帧的Mask都被设置为1。

9-15位(Payload len):表示Payload data的长度。如果值是0~125,则真实长度就是前7位表示;如果值是126,则真实长度就是后16位(Extended payload length 126);如果值是127,则真实长度就是后64位(Extended payload length 127)

2.2 报文样例

- ping帧,Opcode=9,Mask=1,Payload len=0,Masking-Key有内容

- pong帧,Opcode=10,Mask=0,Payload len=0,Masking-Key为空

- 文本帧,Opcode=1,Mask=0,Payload len=84,Masking-Key为空

Part 03●  代码实现 

接下来,一起动手编写WebSocket服务端和客户端,这里提供一个java版的服务端demo和一个html版的客户端demo。

1、服务端demo是一个springboot项目

- 引用spring-boot-starter-websocket依赖

<!-- WebSocket --><dependency>  <groupId>org.springframework.boot</groupId>  <artifactId>spring-boot-starter-websocket</artifactId></dependency>

- session管理

public class WsSessionManager {

    public static ConcurrentHashMap<String, WebSocketSession> SESSION_POOL = new ConcurrentHashMap<>();

    public static void add(String key, WebSocketSession session) {        SESSION_POOL.put(key, session);    }

    public static WebSocketSession remove(String key) {        return SESSION_POOL.remove(key);    }

    public static void removeAndClose(String key) {        WebSocketSession session = remove(key);        if (session != null) {            try {                session.close();            } catch (IOException e) {                e.printStackTrace();            }        }    }

    public static WebSocketSession get(String key) {        return SESSION_POOL.get(key);    }}

- 消息处理

@Component@Slf4jpublic class MyWsHandler extends AbstractWebSocketHandler {

    @Override    public void afterConnectionEstablished(WebSocketSession session) throws Exception {        log.info("建立ws连接,sessionId:{}", session.getId());        WsSessionManager.add(session.getId(), session);    }

    @Override    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {        // 获得客户端传来的消息        String payload = message.getPayload();        log.info("server 接收到消息, sessionId " + session.getId() + ", payload: " + payload);        session.sendMessage(new TextMessage("server 发送给的消息 " + payload + ",发送时间:" + LocalDateTime.now().toString()));    }

    @Override    protected void handleBinaryMessage(WebSocketSession session, BinaryMessage message) {        log.info("发送二进制消息, sessionId " + session.getId());    }

    @Override    public void handleTransportError(WebSocketSession session, Throwable exception) {        log.error("异常处理, sessionId " + session.getId());

- WebSocket配置

@Configuration@EnableWebSocketpublic class WsServerConfig implements WebSocketConfigurer {

    @Autowired    private MyWsHandler myWsHandler;

    @Override    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {        registry.addHandler(myWsHandler, "myWs")                //允许跨域                .setAllowedOrigins("*");    }

}

2、客户端demo是一个html网页

<!doctype html><form name="publish">  <input type="text" name="message" maxlength="50"/>  <input type="submit" value="Send"/></form>

<div id="messages"></div>

<script>let url='ws://127.0.0.1:8889/myWs';let socket = new WebSocket(url);

// send message from the formdocument.forms.publish.onsubmit = function() {  let outgoingMessage = this.message.value;  socket.send(outgoingMessage);  return false;};

// handle incoming messagessocket.onmessage = function(event) {  let incomingMessage = event.data;  showMessage(incomingMessage);};

socket.onclose = event => console.log(`Closed ${event.code}`);

// show message in div#messagesfunction showMessage(message) {  let messageElem = document.createElement('div');  messageElem.textContent = message;  document.getElementById('messages').prepend(messageElem);

Part 04●  结束语 

WebSocket适用于服务器端需要快速向浏览器发送消息的场景,例如网页游戏、视频网站、在线文档、运维工具等。浏览器可以看做是一个瘦客户端,它不提供直接操作tcp长连接的编程接口,也无法简单地集成消息组件客户端。在使用浏览器作为客户端的场景下,WebSocket是最常用的服务器端主动推送方案。

当然,有很多种技术可以实现服务器端向客户端主动推送消息,WebSocket只是其中一种,其他常见的方案还有tcp长连接、消息组件(如mqtt、kafka)等,不过各有优缺点,这个可以在日后进一步学习。

推荐器件

更多器件
器件型号 数量 器件厂商 器件描述 数据手册 ECAD模型 风险等级 参考价格 更多信息
DP83867ERGZR 1 Texas Instruments Extended temperature, robust low-latency gigabit Ethernet PHY transceiver with SGMII 48-VQFN -40 to 105

ECAD模型

下载ECAD模型
暂无数据 查看
TJA1051T/3/CM,118 1 NXP Semiconductors TJA1051 - High-speed CAN transceiver SOIC 8-Pin

ECAD模型

下载ECAD模型
$1.03 查看
TJA1021T/20/C,118 1 NXP Semiconductors TJA1021 - LIN 2.1/SAE J2602 transceiver SOIC 8-Pin

ECAD模型

下载ECAD模型
$1.51 查看

相关推荐

电子产业图谱

移动Labs是中国移动的社交化新媒体平台,是面向外部行业及产业链合作伙伴的信息发布、业务发展和产业推进门户。