封包
数据封包协议规定:整个数据包包含2字节长度信息+数据包体。2字节长度信息包含本身着2字节。如:数据体是(abcdefg)7个字节,整体封包就是09abcdefg,总共是9个字节的协议
1、netbus接收到数据后发送到static void on_recv_tcp_data(uv_session* s),数据包含在session管理里面s->recv_buf和s->recved两个属性是这个session收取的数据信息
static void on_recv_tcp_data(uv_session* s){
unsigned char* pkg_data = (unsigned char*)((s->long_pkg != NULL) ? s->long_pkg : s->recv_buf);
while (s->recved > 0){
int pkg_size = 0;
int head_size = 0;
if (!tcp_protocol::read_header(pkg_data, s->recved, &pkg_size, &head_size)){
break; //如果读不到头,就继续收数据
}
if (s->recved < pkg_size){ //数据不够一个数据包,继续收数据
break;
}
//至少收到了一个完整的数据包
unsigned char* raw_data = pkg_data + head_size; //数据包的起始内存地址,去掉长度
on_recv_client_cmd((session*)s, raw_data, pkg_size - head_size); //处理数据
if (s->recved > pkg_size){ //如果recved大于pkg_size,除了这一个完整的包外,还有其他数据,
memmove(pkg_data, pkg_data + pkg_size, s->recved - pkg_size); //处理一个完整数据包后,把后面的未处理数据移动到头部,下一轮循环处理
}
//recved的数据最少要等于pkg_size,所以recved不可能小于0,如果recved小于pkg_size上边一个条件判断就会中断了
s->recved -= pkg_size;
if (s->recved == 0 && s->long_pkg != NULL){
free(s->long_pkg);
s->long_pkg = NULL;
s->long_pkg_size = 0;
}
//end
}
}
2、pkg_data是因为数据包体可能超过协议长度RECV_LEN,所以会启用long_pkg,来处理很大的包
下面是一个死循环用来处理接收到的数据(大包处理具体请看https://blog.csdn.net/qq_28710983/article/details/83045843这边文章)
3、read_header函数根据封包协议解析出数据包长度信息
bool tcp_protocol::read_header(unsigned char* data, int data_len,int* pkg_size, int* out_head_size){
if (data_len < 2){
//没有办法读取包的大小,前两个自己位一个包的长度
return false;
}
*pkg_size = ((data[0]) | (data[1] << 8));
*out_head_size = 2;
return true;
}
TCP数据包有粘包问题,接收的数据可能有以下几种情况
收到一个完整数据包的情况下(假设收到的数据封包为09abcdefg)
1、read_header是用来读取包长度信息的,因为规定2字节是长度信息,所以如果收到的信息没有2字节就没有办法解析出长度,所以跳出循环继续接收数据,否则就根据前2字节解析出pkg_size和head_size,head_size永远为2字节,这个是规定
2、if (s->recved < pkg_size) 这时解析出的pkg_size是9,s->recved = 9条件通过往下执行
3、前面判断通过说明数据接收完成s->recved = 9,raw_data = pkg_data + head_size ,这里raw_data就是数据包体的内存起始地址,因为前2字节是长度信息,(09abcdefg)用这个为例,假如从100为第一个字母地址,那么数据包的起始地址a就是102,那么raw_data的起始地址就是102
4、前面判断都通过,那么就至少解析到了1整个数据包,就进入 void on_recv_client_cmd(session* s, unsigned char* body, int len)函数处理数据
5、处理完成数据后,判断s->recved > pkg_size除了这个数据包,是否还有其他数据,这里s->recved = 9,pkg_size = 9,条件不通过,往下执行
6、s->recved -= pkg_size , s->recved = 0;
7、while循环条件不成立跳出循环
收到1.5个协议包的情况(09abdefg091234)
1、read_header是用来读取包长度信息的,因为规定2字节是长度信息,所以如果收到的信息没有2字节就没有办法解析出长度,所以跳出循环继续接收数据,否则就根据前2字节解析出pkg_size和head_size,head_size永远为2字节,这个是规定
2、if (s->recved < pkg_size) 这时解析出的pkg_size是9,s->recved = 15条件通过往下执行
3、前面判断通过说明数据接收完成s->recved = 15,raw_data = pkg_data + head_size ,这里raw_data就是数据包体的内存起始地址,因为前2字节是长度信息,(09abcdefg)用这个为例,假如从100为第一个字母地址,那么数据包的起始地址a就是102,那么raw_data的起始地址就是102
4、进入on_recv_client_cmd处理数据
5、处理完成数据后,判断s->recved > pkg_size除了这个数据包,是否还有其他数据,这里s->recved = 15,pkg_size = 9,条件通过,下面是目前内存分布情况
执行memmove函数,memmove(pkg_data, pkg_data + pkg_size, s->recved - pkg_size),前面一个数据封包已经处理好,下次要处理第二个数据封包,on_recv_ws_data每次都是从s->recv_buf的起始位置开始处理,所以需要把第二个封包移动到recv_buf的起始为位置,第二个数据包的起始地址是recv_buf的起始地址100 再加上第一个数据封包的长度9,所以第二个数据封包的起始地址就是recv_buf + pkg_size ,pkg_data就是recv_buf,所以等于pkg_data + pkg_size,移动数据长度是剩下没有处理的数据的长度s->recved - pkg_size = 15 - 9 = 6,移动6个字节,这样就把第二个数据封包移动到s->recv_buf的起始地址
6、s->recved -= pkg_size , s->recved = 6表示还有6个字节长度没有处理完成,继续while循环,当执行完成read_header函数后解析出第二个数据封包长度为9,但是剩余长度只剩下6,还有3字节没有接收完成,所以到if (s->recved < pkg_size)判断的时候跳出while循环,netbus继续接收数据
相关阅读
相信大多数朋友都是会使用WPE的,因为这里也有不少好的教程,大家都辛苦了!先说说接触WPE的情况。当时好像是2011年,我本来不知道WPE对
传统的ROM制作都要对system.img进行手动解压,修改,封包,现在教你一键操作,完成ROM制作全部流程,本文主要用到了rom定制大师工具,在本文