WebSocket

一、什么是WebSocket?

WebSocket 是一种在单个TCP连接上进行全双工通信的协议。WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。

在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接, 并进行双向数据传输。(维基百科)

WebSocket本质上一种计算机网络应用层的协议,用来弥补http协议在持久通信能力上的不足。

WebSocket 协议在2008年诞生,2011年成为国际标准。现在最新版本浏览器都已经支持了。

它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。

WebSocket 的其他特点包括:

(1)建立在 TCP 协议之上,服务器端的实现比较容易。

(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。

(3)数据格式比较轻量,性能开销小,通信高效。

(4)可以发送文本,也可以发送二进制数据。

(5)没有同源限制,客户端可以与任意服务器通信。

(6)协议标识符是ws(如果加密,则为wss),服务器网址就是 URL。

二、WebSocket工作原理

握手阶段

浏览器先通过一个特殊的 HTTP 请求(带有 Upgrade: websocket 头)向服务器发起连接请求。

如果服务器支持 WebSocket,就会返回一个确认响应(101 Switching Protocols),表示协议升级成功。

建立连接

握手完成后,HTTP 协议升级为 WebSocket 协议。

此时,客户端与服务器之间形成一个持久连接,双方都可以随时主动发送数据。

双向通信

客户端可以向服务器主动发送消息。

服务器也可以主动向客户端推送数据。

所有消息都通过这个持续存在的连接传输,无需频繁建立连接。

关闭连接

当一方发送关闭信号时,连接被终止。

三、WebSocket与HTTP的区别

HTTP(传统方式)

一次请求 → 一次响应 → 连接关闭

必须客户端先发请求

适合:网页加载、接口请求

WebSocket(实时通信)

建立连接后一直保持

客户端和服务器都可以主动发消息

低延迟、高效率

WebSocket 的特点

双向通信(客户端 ⇄ 服务器)

实时性强(延迟低)

长连接(不会频繁断开)

减少开销(不需要反复建立连接)

对比 HTTP WebSocket
通信方式 请求响应 双向通信
是否实时 差 强
连接方式 短连接 长连接
延迟 较高 很低
开销 大 小
开发复杂度 低 高
适合 CRUD 实时系统

四、WebSocket的优点和缺点

WebSocket 的优点

真正实时通信(最大优点)

HTTP:

客户端请求一次

服务器回复一次

WebSocket:

服务器可以主动发消息

例如:

聊天消息

机器人状态

游戏同步

都能实时推送。

双向通信

HTTP:

只能客户端主动请求

WebSocket:

客户端 ⇄ 服务端

双方都能主动发送

这是本质区别。

长连接(性能高)

HTTP 每次都:

建立TCP

发送

断开

WebSocket:

建立一次

一直保持

所以:

延迟低

CPU 消耗小

网络开销小

非常适合高频通信

比如:

位置更新 30 次

机器人每秒:

如果用 HTTP:

30 次请求

太浪费。

WebSocket:

一个连接持续发

效率极高。

支持二进制数据

不仅能传字符串。

还能传:

图片

音频

视频

protobuf

激光雷达数据

延迟非常低

因为:

不用频繁握手

所以特别适合:

游戏

机器人控制

实时监控

WebSocket的缺点

长连接占资源(最大缺点)

HTTP:

请求结束连接关闭

WebSocket:

连接一直存在

如果:

10万个客户端

服务器就要维护:

10万个 socket

这很吃:

内存

文件描述符

CPU

服务器开发复杂

HTTP:

请求 → 响应

很简单。

WebSocket:

需要处理:

长连接

心跳

重连

断线检测

并发

异步IO

复杂很多。

五、用C++写基础的WebSocket服务端和客户端

Websocket的服务端

server.cpp

cpp 复制代码
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>

#include <iostream>

typedef websocketpp::server<websocketpp::config::asio> server;

using websocketpp::connection_hdl;

class WebSocketServer
{
public:
    WebSocketServer()
    {
        // 初始化 ASIO
        m_server.init_asio();

        // 设置消息回调
        m_server.set_message_handler(
            [this](connection_hdl hdl, server::message_ptr msg)
            {
                on_message(hdl, msg);
            });
    }

    void run(uint16_t port)
    {
        // 监听端口
        m_server.listen(port);

        // 开始接受连接
        m_server.start_accept();

        std::cout << "WebSocket Server start at port "
                  << port << std::endl;

        // 启动服务
        m_server.run();
    }

private:
    server m_server;

    void on_message(connection_hdl hdl,
                    server::message_ptr msg)
    {
        std::cout << "收到消息: "
                  << msg->get_payload()
                  << std::endl;

        // 回复客户端
        m_server.send(hdl,
                      "服务器收到消息: " + msg->get_payload(),
                      websocketpp::frame::opcode::text);
    }
};

int main()
{
    WebSocketServer server;

    server.run(9002);

    return 0;
}

Websocket的客户端

Client.cpp

cpp 复制代码
#include <websocketpp/config/asio_no_tls_client.hpp>
#include <websocketpp/client.hpp>

#include <iostream>

typedef websocketpp::client<websocketpp::config::asio_client> client;

using websocketpp::connection_hdl;

class WebSocketClient
{
public:
    WebSocketClient()
    {
        m_client.init_asio();

        // 连接成功回调
        m_client.set_open_handler(
            [this](connection_hdl hdl)
            {
                on_open(hdl);
            });

        // 消息回调
        m_client.set_message_handler(
            [this](connection_hdl hdl,
                   client::message_ptr msg)
            {
                on_message(hdl, msg);
            });
    }

    void connect(const std::string& uri)
    {
        websocketpp::lib::error_code ec;

        auto con = m_client.get_connection(uri, ec);

        if (ec)
        {
            std::cout << "连接失败: "
                      << ec.message()
                      << std::endl;
            return;
        }

        m_client.connect(con);

        m_client.run();
    }

private:
    client m_client;

    void on_open(connection_hdl hdl)
    {
        std::cout << "连接成功" << std::endl;

        // 发送消息
        m_client.send(hdl,
                      "你好,我是客户端",
                      websocketpp::frame::opcode::text);
    }

    void on_message(connection_hdl hdl,
                    client::message_ptr msg)
    {
        std::cout << "收到服务端消息: "
                  << msg->get_payload()
                  << std::endl;
    }
};

int main()
{
    WebSocketClient client;

    client.connect("ws://localhost:9002");

    return 0;
}
相关推荐
要吃这碗饭4 小时前
深入理解 TCP 协议:从三次握手到可靠传输
网络·网络协议·tcp/ip
和裕4 小时前
全纸结构重型纸箱能否满足 1 吨以上设备出口熏蒸豁免要求?通关合规性全解析
大数据·运维·网络·人工智能·算法
呉師傅6 小时前
得力P2500、M2500系列打印机硒鼓加粉及清零方法【纯享版】
运维·网络·windows·电脑
大侠归来7 小时前
TCP/IP 网络编程:多播与广播
网络·tcp/ip·智能路由器
Zelman7 小时前
HTTPS 协议
网络协议·https
weixin_416667968 小时前
银河麒麟V10看门狗试验-1
网络·chrome·python
白帽攻防录8 小时前
SRC 挖洞:WSO2 JWT 算法混淆绕过深度复盘,CVE-2026-5430 不支持的算法怎么变成管理员
网络·算法·安全·网络安全·jwt
starzy19908 小时前
Flink 优化之网络缓存优化及参数详解:从数据传输机制到反压原理的生产调优指南
网络·缓存·flink
正经教主9 小时前
【FDE系列】阶段3:Day 58:Prompt 安全 — 注入、越狱与防护
网络·人工智能·安全·prompt·fde
实点科技10 小时前
实点科技IO-Link I/O IOL7A/B系列参数配置方法介绍
网络