ZBLOG

如何实现webscoket

WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,适用于实时应用(如聊天、游戏、实时数据推送等)。以下是基于 C++ 实现 WebSocket 的核心步骤和示例代码:


1. 核心实现步骤

(1) 建立 TCP 服务端

  • 使用 Socket API 监听端口(如 8080)。
  • 接受客户端连接,获取文件描述符(fd)。

(2) HTTP 升级到 WebSocket

  • 客户端发送 HTTP Upgrade 请求:
    1. GET /chat HTTP/1.1
    2. Host: example.com
    3. Upgrade: websocket
    4. Connection: Upgrade
    5. Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    6. Sec-WebSocket-Version: 13
  • 服务端响应: 计算 Sec-WebSocket-Accept:对客户端 Key + GUID 258EAFA5-E914-47DA-95CA-C5AB0DC85B11做 SHA1+Base64。 返回响应:
  1. HTTP/1.1 Switching Protocols
  2. Upgrade: websocket
  3. Connection: Upgrade
  4. Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=

(3) WebSocket 数据帧解析

WebSocket 数据帧格式(RFC6455):

  1. 0 1 2 3
  2. 0 |1|2|3|4|5|6|7|8|9|0|1|2|3|4|
  3. +-+-+-+-+-------+-+-------------+
  4. FIN |RSV | OPCODE | MASKED? |
  5. +-+-+-+-+-------+-+-------------+
  6. Payload Length (7/16/64 bits)
  7. Extended Payload Length (if needed)
  8. Masking Key (4 bytes, if MASKED=1)
  9. Payload Data (application data)

关键字段:

  • OPCODE0x01(文本)、0x02(二进制)、0x08(关闭连接)。
  • MASKED:客户端消息必须掩码处理,服务端无需掩码。

2. C++ WebSocket Server Demo

以下是一个简化版实现(需自行处理错误检查和优化):

  1. #include <iostream>
  2. #include <string>
  3. #include <sys/socket.h>
  4. #include <netinet/in.h>
  5. #include <unistd.h>
  6. #include <openssl/sha.h>
  7. #include <base64/base64.h> // Base64库需自行引入
  8. // WebSocket握手响应生成函数
  9. std::string generate_ws_accept(const std::string& client_key) {
  10. const std::string magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
  11. std::string combined = client_key + magic;
  12. unsigned char sha_hash[SHA_DIGEST_LENGTH];
  13. SHA1((const unsigned char*)combined.c_str(), combined.size(), sha_hash);
  14. return base64_encode(sha_hash, SHA_DIGEST_LENGTH);
  15. }
  16. int main() {
  17. int server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  18. sockaddr_in addr{AF_INET, htons(8080), INADDR_ANY};
  19. bind(server_fd, (sockaddr*)&addr, sizeof(addr));
  20. listen(server_fd, SOMAXCONN);
  21. while (true) {
  22. int client_fd = accept(server_fd, nullptr, nullptr);
  23. char buffer[1024] = {0};
  24. read(client_fd, buffer, sizeof(buffer));
  25. // Step2: HTTP升级为WebSocket协议并回复握手包.
  26. if (strstr(buffer,"Upgrade: websocket")){
  27. //提取Sec - WebSoket - Key值.
  28. std::string key(buffer);
  29. size_t start=key.find("Sec - Websoket - Key : ") +19;
  30. size_t end=key.find("\r\n",start);
  31. std :: string client_key=key.substr(start,end-start);
  32. //生成应答并发送HTTP101切换协议.
  33. std :: string accept_key=generate_ws_accept(client_key);
  34. std :: string response="HTTP /1 .1101 Switching Protocols\r\n"
  35. "Upgrade : websoket\r\n"
  36. "Connection : Upgrade\r\n"
  37. "Sec - Websoket - Accept:"+accept_key+"\r\n\r\n";
  38. send(client_fd ,response.c_str(),response.size(),MSG_NOSIGNAL);
  39. //Step3 :处理后续的WS数据帧...
  40. while(true){
  41. uint8_t ws_header[14];//最大可能头部长度14字节.
  42. recv(client_fd,&ws_header,sizeof(ws_header),MSG_PEEK);//偷看头部.
  43. bool is_masked=(ws_header [l] &128)==128;//检查MASK位.
  44. uint64_t payload_len=(uint8_t)( ws_header[l ] &127);//有效载荷长度.
  45. if(payload_len ==126){//扩展16位长度.
  46. payload_len=ntohs(*reinterpret_cast<uint16_t*>(& ws_header [2]));
  47. }else if(payload_len ==127){//扩展64位长度.
  48. payload_len=ntohll(*reinterpret_cast<uint64_t*>(& ws_header [2]));
  49. }
  50. //读取完整帧并处理掩码和数据...
  51. uint32_t mask_key;
  52. if(is_masked){
  53. memcpy(&mask_key,& ws_header [payload_len >126 ?4 :2],sizeof(mask_key));//获取掩码键值.
  54. }
  55. ...
  56. }
  57. }
  58. close(client_fd);
  59. }
  60. }

3.推荐开源库

直接使用现有库更高效:

(a)轻量级方案

-Boost.Asio + Beast:参考文档

  1. websocket::stream<tcp::socket> ws(ioc);
  2. ws.accept(request); //自动完成握手和数据帧解析。

(b)高性能方案

-uWebSocketsGitHub

  1. uWS::App().ws("/*", {...}).listen(9000);

4.Websocket关键点总结

协议升级 通过HTTP101状态码切换协议。
数据分帧 需按RFC6455解析掩码、长度和操作码。
心跳保活 定期发送Ping/Pong帧维持连接。
多线程优化 建议结合IO多路复用(epoll/kqueue)。

如果需要完整项目代码或深入某个环节,可以进一步讨论! 🚀


内容由零声教学AI助手提供,问题来源于学员提问

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://golang.0voice.com/?id=23085

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?