web socket RFC6455 frame 打包、解包

本文主要探讨了WebSocket协议中RFC6455帧的打包和解包过程,重点关注在大部分环境中常见的payload_len不超过127的情况。在解包成功后,相关函数如get_head_len、get_total_len、get_payload_len能正确返回数据。当unpackage返回值大于0时,调用与长度相关的函数将被视为非法操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

#ifndef __APP_WEBSOCKET_FRAME_H__
#define __APP_WEBSOCKET_FRAME_H__
#include "memory.hpp"

class buffer;

struct websocket_frame
{
	websocket_frame();
	~websocket_frame();
	static const unsigned int fix_min_len = 2;
	static const unsigned int fix_masking_len = 4;
	static const unsigned int fix_126_len = 2;
	static const unsigned int fix_127_len = 8;
	bool fin;
	bool rsv1;
	bool rsv2;
	bool rsv3;
	unsigned char opcode;
	bool mask;
	unsigned char payload_len ;
	unsigned short payload_126_len;
	unsigned long long payload_127_len;
	unsigned char   masking_key[4];
	shared_ptr<buffer> payload;

	unsigned int get_head_len() const ;
	unsigned int get_total_len() const ;
	unsigned int get_payload_len() const ;
	//解包
	int unpakcage( const shared_ptr<buffer> & buf );

	//打包
	unsigned int package_size() ;
	shared_ptr<buffer> package() ;
protected:
	void set_masking_key( unsigned char * data, int offset);
	void get_masking_key( unsigned char * data, int offset);

};
#endif


#include "websocket_frame.hpp"
#include "buffer_pool.hpp"
#include <cstring>
#include <glog/logging.h>
#include <cstdlib>

websocket_frame::websocket_frame():fin(false)
,rsv1(false),rsv2(false),rsv3(false),mask(false),opcode(0)
,payload_len(0),payload_126_len(0),payload_127_l
<think>好的,用户想用C语言实现WebSocket的心跳机制,并需要示例代码。首先,我得回忆一下WebSocket协议的基本结构和心跳机制的作用。心跳包通常用来保持连接活跃,防止因长时间无数据交换而被防火墙或路由器断开。根据RFC 6455,心跳帧是Ping和Pong类型的控制帧,客户端或服务器可以发送Ping帧,对方必须回应Pong帧。 用户提到的引用资料里,引用[2]提到C++的实现,但用户需要C语言。虽然引用中没有直接的C代码,但可以参考其思路。比如,处理WebSocket协议的解包和封包是关键。C语言需要手动管理内存和网络层,这可能比较复杂。 首先,我需要确定心跳机制的实现步骤。应该包括定时发送Ping帧,接收Pong帧,以及处理超时。在C语言中,可以使用定时器或者多线程来处理定时任务。例如,在主循环中设置一个定时器,每隔一段时间发送Ping。 接下来是WebSocket帧的构造。Ping帧的opcode是0x9,Pong帧是0xA。发送Ping帧时,需要按照WebSocket的帧格式封装数据。比如,第一个字节是FIN位和opcode,第二个字节是掩码和载荷长度,然后是掩码密钥和载荷数据。不过根据RFC,Ping和Pong帧的载荷长度不能超过125字节,所以可以处理为短帧。 然后,处理接收到的帧。当接收到Ping帧时,必须回复一个Pong帧,载荷数据与接收的Ping相同。如果收到Pong帧,可以记录最后一次活动时间,用于检测连接是否存活。 用户可能遇到的难点在于网络层的处理,比如非阻塞IO、定时器集成以及粘包处理。引用[2]中提到针对TCP粘包做了处理,确保读取完整的WebSocket包后才处理。C语言中可能需要自己处理缓冲区,逐步解析收到的数据。 示例代码方面,需要展示如何构造Ping帧,如何解析接收的Pong帧。同时,心跳检测的逻辑,比如设置超时时间,如果超过一定时间未收到Pong,则断开连接。 另外,引用[3]提到断网重连和自动心跳,可能需要在代码中加入重连机制和心跳间隔设置。但用户主要关注心跳的实现,所以示例代码可能集中在发送和接收部分。 需要注意,C语言没有内置的WebSocket库,所以需要手动处理加密部分,比如握手时的Sec-WebSocket-Key的哈希处理,这可能涉及SHA1和Base64编码。但心跳机制在握手之后,所以可能不需要这部分,但需要确保连接已经建立。 总结步骤:1. 定时发送Ping帧;2. 监听Pong帧;3. 超时处理。代码需要包括帧的构建、发送、接收解析,以及定时机制。可能需要使用select或poll来处理超时,或者多线程配合信号。 最后,示例代码可能需要简化,只展示核心部分,比如发送Ping和处理Pong的函数,以及超时检查。同时提醒用户注意网络层的实现细节,如缓冲区和粘包处理。</think>### 分步解答:C语言实现WebSocket心跳机制 #### 一、心跳机制原理 WebSocket心跳通过定期发送$Ping$帧(opcode 0x9)和接收$Pong$帧(opcode 0xA)维持连接活性。核心流程如下: 1. 服务端/客户端周期性发送$Ping$帧 2. 接收方必须回复相同载荷的$Pong$帧 3. 超时未收到响应则主动断开连接[^1] #### 二、关键代码实现 以下为C语言实现心跳的核心逻辑(需结合网络层): ```c // WebSocket帧头定义 typedef struct { unsigned char fin; unsigned char opcode; unsigned char mask; uint64_t payload_len; unsigned char masking_key[4]; } ws_frame_header; // 发送Ping帧 void send_ping(int socket_fd) { unsigned char ping_frame[6] = { 0x89, // FIN + Ping opcode (0x9) 0x00 // Mask位设为0,长度0 }; send(socket_fd, ping_frame, 2, 0); } // 接收处理Pong帧 int handle_pong(unsigned char* data, size_t len) { ws_frame_header header; // 解析帧头(需实现帧解析函数) parse_frame_header(data, &header); if (header.opcode == 0xA) { // Pong帧 printf("Received PONG\n"); return 1; } return 0; } // 心跳检测线程 void* heartbeat_thread(void* arg) { int timeout_counter = 0; while(1) { sleep(HEARTBEAT_INTERVAL); // 心跳间隔(如30秒) send_ping(socket_fd); timeout_counter++; if(timeout_counter > MAX_TIMEOUT) { close(socket_fd); break; } } return NULL; } ``` #### 三、实现要点 1. **帧构造**: - $Ping$帧:第一个字节为`0x89`(FIN=1 + opcode 0x9) - $Pong$帧:第一个字节为`0x8A`(FIN=1 + opcode 0xA) - 载荷长度需遵守协议限制(≤125字节)[^2] 2. **定时机制**: - 使用`select()`或`poll()`实现非阻塞超时检测 - 或创建独立线程管理心跳周期 3. **粘包处理**: ```c // 示例粘包处理逻辑 while(bytes_received > 0) { if(current_pos < 2) { // 未读够帧头 break; } parse_frame_header(buffer, &header); full_length = header.payload_len + 2; // 基础长度 if(bytes_received < full_length) { break; // 等待完整帧 } process_frame(buffer); // 处理完整帧 } ``` #### 四、调试建议 1. 使用Wireshark抓包验证帧格式 2. 增加调试日志输出帧内容 3. 测试网络中断后的重连机制[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值