web socket RFC6455 frame 打包、解包

#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_len(0)
{
	int rand_var = rand();
	masking_key[0] = (rand_var & 0xff000000)>>24;
	masking_key[1] = (rand_var & 0x00ff0000) >> 16;
	masking_key[2] = ( rand_var & 0x0000ff00) >> 8;
	masking_key[3] = rand_var & 0x000000ff;
}
websocket_frame::~websocket_frame(){
	if( payload ){
		recycle_buffer(payload);
	}
}

void websocket_frame::set_masking_key( unsigned char * data, int offset){
			masking_key[0] = data[0+offset];
			masking_key[1] = data[1+offset];
			masking_key[2] = data[2+offset];
			masking_key[3] = data[3+offset];
	}
void websocket_frame:: get_masking_key( unsigned char * data, int offset){
		 data[0+offset] = masking_key[0];
		 data[1+offset] = masking_key[1] ;
		 data[2+offset] = masking_key[2];
		 data[3+offset] = masking_key[3] ;
}
unsigned int websocket_frame::get_head_len() const {
	return get_total_len() - get_payload_len();
}
unsigned int websocket_frame::get_total_len() const {
	if( mask ){
		if( payload_len < 126 ){
		return payload_len + fix_min_len + fix_masking_len;
		}else if( payload_len == 126 ){
			return payload_126_len + fix_min_len + fix_masking_len + fix_126_len;
		}else {
			return payload_127_len +fix_min_len + fix_masking_len + fix_127_len;
		}
	}else{
		if( payload_len < 126 ){
			return payload_len + fix_min_len;
		}else if( payload_len == 126 ){
			return payload_126_len + fix_min_len + fix_126_len;
		}else {
			return payload_127_len + fix_min_len + fix_127_len;
		}
	}
}
unsigned int websocket_frame::get_payload_len() const {
	if( payload_len < 126 ){
		return payload_len;
	}else if( payload_len == 126 ){
		return payload_126_len;
	}else {
		return payload_127_len;
	}
}
int websocket_frame::unpakcage( const shared_ptr<buffer> & buf ){
	if( buf->length() == 0 ){
		return 2;
	}
	unsigned char * data = buf->data();

	fin = data[0] & 0x80;
	rsv1 = data[0] & (0x40  );
	rsv2 = data[0] & ( 0x20);
	rsv3 = data[0] & ( 0x10);
	opcode = (data[0] & 0x0f) ;

	mask = data[1] & 0x80;
	payload_len = data[1] & 0x7f;

	if( payload_len < 126 ){
		if( buf->length() < get_total_len() ){
			return get_total_len() - buf->length();
		}
		payload = get_buffer( get_payload_len());
		unsigned char * pdata = payload->data();
		if( mask ){
			set_masking_key(data,2);

			int i;
			for( i = 0 ; i < payload_len; i ++ ){
				pdata[i] = data[6+i] ^ masking_key[i%4];
			}
		}else{
			memcpy(pdata, data+2, get_payload_len());
		}
		payload->size(get_payload_len());
	}else if( payload_len == 126 ){
		if( buf->length() < 4 ){
			return 4 - buf->length();
		}
		payload_126_len = (data[2] << 8 )| data[3];
		if( buf->length() < get_total_len() ){
			return get_total_len() - buf->length();
		}
		payload = get_buffer( get_payload_len());
		unsigned char * pdata = payload->data();
		if( mask ){
			set_masking_key(data,4);
			int i;
			for( i = 0 ; i < payload_126_len; i ++ ){
				pdata[i] = data[8+i] ^ masking_key[i%4];
			}
		}else{
			memcpy(pdata, data+4, get_payload_len());
		}
		payload->size(get_payload_len());
	}else{ // 127
		LOG(FATAL)<<"un support big frame for websocket.";
	}
	return 0;
}

unsigned int websocket_frame::package_size() {
	if( payload->length() < 126 ){
		payload_len = payload->length();
	}else if( payload->length() < 0xffff ){
		payload_len = 126;
		payload_126_len = payload->length();
	}else{
		payload_len = 127;
		payload_127_len = payload->length();
	}
	return get_total_len();
}

shared_ptr<buffer> websocket_frame::package() {
	shared_ptr<buffer> buf = get_buffer( package_size());
	buf->size(package_size());

	unsigned char * data = buf->data();

	data[0] = 0;
	if( fin ){
		data[0] |= 0x80;
	}
	if( rsv1 ){
		data[0] |= 0x40;
	}
	if( rsv2 ){
		data[0] |= 0x20;
	}
	if( rsv3 ) {
		data[0] |= 0x10;
	}
	data[0] |= (opcode & 0x0f);

	data[1] = 0;
	if( mask ){
		data[1] |= 0x80;
	}
	data[1] |=( payload_len & 0x7f);
	unsigned char * pdata = payload->data();
	if( payload_len < 126 ){
		if( mask ){
			//get_masking_key(data,2);
			data[2] = masking_key[0];
			data[3] = masking_key[1];
			data[4] = masking_key[2];
			data[5] = masking_key[3];
			int i = 0;

			for( i = 0 ; i < payload_len; i ++ ){
				data[6+i] = pdata[i] ^ masking_key[i%4];
			}
		}else{
			memcpy(data+2, pdata,payload_len);
		}
	}else if( payload_len == 126 ){
		data[2] =(unsigned char)( (payload_126_len & 0xff00) >> 8);
		data[3] =(unsigned char) (payload_126_len & 0x00ff);

		if( mask ){
			data[4] = masking_key[0];
			data[5] = masking_key[1];
			data[6] = masking_key[2];
			data[7] = masking_key[3];
			int i = 0;

			for( i = 0 ; i < payload_126_len; i ++ ){
				data[8+i] = pdata[i] ^ masking_key[i%4];
			}
		}else{
			memcpy(data+4, pdata,payload_126_len);
		}
	}else if( payload_len == 127 ){
		LOG(FATAL)<<"no support 127 web socket frame.";
	}

	return buf;
}

重点在unpakcage方法,该方法在解包成功时,返回0,失败时,返回还需要多少字节才可以解析一个完整的包。

另外暂时没有计算payload_len=127情况下,主要是大部分环境下不需要用到那么大。解包成功后,get_head_len、get_total_len、get_payload_len调用时,都可以返回正确的数据,如果unpackage返回大于0时,调用关于len的函数是属于非法的。。

web socket RFC6455 frame 打包、解包,布布扣,bubuko.com

时间: 2025-01-13 23:37:47

web socket RFC6455 frame 打包、解包的相关文章

web socket RFC6455 connection --asio C++11

#ifndef __APP_WEBSOCKET_CONNECTION_H__ #define __APP_WEBSOCKET_CONNECTION_H__ #include <asio.hpp> #include "tcp_connection.hpp" class websocket_connection : public tcp_connection { public: websocket_connection( const std::tr1::shared_ptr&l

(转)基于RTP的H264视频数据打包解包类

最近考虑使用RTP替换原有的高清视频传输协议,遂上网查找有关H264视频RTP打包.解包的文档和代码.功夫不负有心人,找到不少有价值的文档和代码.参考这些资料,写了H264 RTP打包类.解包类,实现了单个NAL单元包和FU_A分片单元包.对于丢包处理,采用简单的策略:丢弃随后的所有数据包,直到收到关键帧.测试效果还不错,代码贴上来,若能为同道中人借鉴一二,足矣.两个类的使用说明如下(省略了错误处理过程): DWORD H264SSRC ; CH264_RTP_PACK pack ( H264S

java基础类型包装类与自动打包解包

一基础类型包装类 基础数据类型存放在内存的栈区域,可以通过包装类将基础数据类型转换为引用数据类型,即存储在堆与栈中. 基础数据类型一共有8种,相对应的包装类也有8种.分别是Byte,Short,Integer,Long,Float,Double,Character,Boolean.类 包装类位于java.Lang包中. 1 public class Test1 { 2 3 public static void main(String[] args) { 4 // TODO Auto-genera

Web Socket rfc6455 握手 (C++)

std::string data((const char*)buf->data(),bytes_transferred); recycle_buffer(buf); std::string key="Sec-WebSocket-Key:"; auto pos = data.find(key); auto posEnd = data.find("\r\n",pos); auto value = data.substr(pos + key.length(),pos

xpack文件打包解包代码库

Github ###概述 xpack是一个文件资源打包工具及类库,可以对多文件进行打包解包. 其使用文件名的hash作为索引,建立hash索引表以加速文件查找. ###特性 支持hashid自动解冲突,即使添加的多个文件名hashid发生冲突也可以正常存取,不用担心文件名hash一样导致的添加失败问题 支持存储文件的原文件名,可以解包复原文件目录结构 支持文件分块存储,可以重复利用被删除文件的剩下的空闲块,提高资源包的空间利用率,提高资源删除的性能 支持寄生资源包,可以把资源包追加到其他文件中,

Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口

Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器内的元素的遍历 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭代器通常被称为"轻量级"对象,因为创建它的代价小. Java中的Iterator功能比较简单,并且只能单向移动: (1) 使用方法iterator()要求容器返回一个I

压缩/打包/解包 命令详解

压缩&解压 gzip gzip 压缩级别1-9 1 压缩级别最低 9压缩级别最高 [默认级别6] 压缩文件类型.gz 压缩:gzip 压缩文件名 [修改压缩级别方法:gzip -1 压缩文件名称] 解压:gzip -d 解压文件名称/gunzip 解压文件名 查看压缩文件:zcat压缩文件名 gzip 只支持文件,不支持目录 bzip2 压缩文件类型.bz2 [也是无法压缩目录.只能压缩文件] 压缩:bzip2 文件名称 解压:bzip2 -d 文件名称/bunzip2 文件名 查看压缩文件:b

打包/解包/压缩

命令: tar 作用: 可以把文件一系列打包到一个大文件中,也可以把打包过的大文件恢复成一系列文件 选项: -z:调用gzip,压缩和解压缩文件 -j:调用bzip2,压缩和解压文件 -c:生成档案文件,创建打包文件 -x:解开档案文件 -v:列出归档解档的详细过程,显示进度 -f:指定档案文件名称,f后面一定是.tar文件,所以必须放选项最后 -C:解压缩到指定目录(要解压缩的目录必须存在) 注意: f选项必须放最后,其他选项顺序随意 使用: # 打包文件(被打包文件可以空格间隔输入多个) t

打包解包

打tar包 tar cvf .tar包名 包源文件 tar cvf task.tar t1 t2 在tar包基础上,打gz包 gzip .tar包:命令运行后,task.tar->task.tar.gz gzip task.tar 将gz包解压为tar包,命令运行后,task.tar.gz->task.tar gzip -d task.tar.gz 查看tar包 tar tvf pack1.tar 解tar包 tar xvf pack1.tar 打gz包,一步到位 tar cvfz task.