1数据分包
在TCP收数据的时候可能会有一个很大的包,这时候很有可能一次就收不完,
或者说一次收到多个数据包,
二进制分包常用的就是size+body的方式;
为了避免服务器被恶意的攻击, 一般会规定一个包的大小上线,
如果超过了,立刻关闭该链接. 比如两个字节表示长度就是64kb
第一次就是提交一个请求
2数据分包实现思路
1先设置一块内存,并设置大小是可以读取的内存数据,如果完成了这个请求
就会返回实际读到的大小,处理完后继续投递请求;
2 发送投递请求的默认大小为8192(1024*8) 也可以是4k就是命令的大小
如果要收收的数据包 小与 8k,可能有两种情况
1 收到的数据大小 大于等于 一个包的数据大小(就是说你可能收到了两个数据包)
处理完整的包,将剩下的不足一个包的数据移动到下一次投递,跳过那部分内容即可。
这就是粘包
2收到的数据只有一个字节,不足header长度,保留继续 投递recv.
3 如果要收的数据>8k 那么肯定第一次收不完,所以,要重新分配一个数据包
大小的内存来保存这个数据包,投递请求的时候,根据这个大小来投递,不多收。
因为已经知道这个大的数据包有多大,收完后才重新投递。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
首先设置这个包的最大上限 如果超过了这个上限 就认定是恶意 数据包 直接断开连接
//左移16位 就是两个字节最大 然后-1
//0000000000000001 1000000000000000 -1 1111111111111111
//转换成16进制0xFFFF 十进制 61440+3840+240+15 65535
#define MAX_PAG_SIZE ((1<<16) - 1) //包的上限制
#define MAX_RECV_SIZE 2048 //一个包的大小
struct
io_package {
WSAOVERLAPPED overlapped;
//重叠结构用于IOCP
WSABUF wsabuffer;
//收数据的缓冲区
int
opt;
// 标记一下我们当前的请求的类型; //事件类型
int
accpet_sock;
int
recv;
//当前io_data 缓冲了多少数据
unsigned
char
* long_pkg;
//处理大的数据包的情况 > MAX_RECV_SIZE
char
pkg[MAX_RECV_SIZE];
//投递百分之90游戏命令的大小
};
|
3现在我规定 前面两个字节是大小 如果只收到一个字节就要继续recv
1
2
3
4
5
6
7
8
9
10
|
io_data->recv += dwTrans;
//当前读取到数据的总大小
if
(io_data->recv < 1)
//收到的数据小于一个字节那就退出 因为包长都获取不到
|