游戏开发论坛

 找回密码
 立即注册
搜索
查看: 26108|回复: 23

tcp中拼包,拆包,粘包,这些问题怎么处理??

[复制链接]

119

主题

1367

帖子

1393

积分

金牌会员

Rank: 6Rank: 6

积分
1393
发表于 2007-10-29 13:15:00 | 显示全部楼层 |阅读模式
我现在用完成端口发送的数据每次不能超过per_io_buffer_size,否则会出错,得要考虑写拆包和拼包的程序了。对于拆包和拼包有什么地方需要注意的?或者有什么好的技巧?

另外对于粘包问题有没有什么好的解决方法?
我这方面经验欠缺有经验的朋友来讨论一下吧。

12

主题

88

帖子

133

积分

注册会员

Rank: 2

积分
133
发表于 2007-10-29 13:36:00 | 显示全部楼层

Re:tcp中拼包,拆包,粘包,这些问题怎么处理??

一般把buffer的大小设置为最大包长的2-4倍,通常buffer4K就可以了.
我们打包的时候在缓冲层面上是应该知道包大小,这样就知道包是否完整.是否粘包.
拆包时候就可以根据包的大小判断是否是完整包,如果是完整包,那么看剩余数据是否还有完整包,完整包提交,
如果最后包不完整就投递read请求继续接收剩余数据.

2万

主题

2万

帖子

6万

积分

论坛元老

Rank: 8Rank: 8

积分
66489
QQ
发表于 2007-10-29 13:40:00 | 显示全部楼层

Re:tcp中拼包,拆包,粘包,这些问题怎么处理??

发送:建立2-3个缓冲区轮换,调用send后,会返回发送成功多少。轮回,直接发完一个缓冲区为止。

接包:建立一个缓冲区,收到后放里面。每个包前4字节声明包是多长,先测缓冲区中够不够4个字节,够的话再看缓冲区中够不够这整个包。够的话取出来。

6

主题

307

帖子

309

积分

中级会员

Rank: 3Rank: 3

积分
309
发表于 2007-10-29 14:05:00 | 显示全部楼层

Re:tcp中拼包,拆包,粘包,这些问题怎么处理??

发数据不需要不需要缓冲,直接拆了提交IOCP就行

接收需要一个缓冲来拼包

6

主题

471

帖子

1047

积分

金牌会员

Rank: 6Rank: 6

积分
1047
发表于 2007-10-29 14:11:00 | 显示全部楼层

Re:tcp中拼包,拆包,粘包,这些问题怎么处理??

用iocp的话尽量用单次异步发送.
先把数据放入缓冲区,发送小于或者等于per_io_buffer_size的数据,等发送成功后再发剩余的数据.
处理粘包,先要定义数据包头信息,比如type,size,flag等,再跟据这些信息在接受时处理消息.
1.接受字节小于包头大小,把数据放入接受缓冲,等待下次接受.
2.接受字节小于包大小,把数据放入接受缓冲,等待下次接受.
3,数据包已完全到达,验证数据包大小,如果正确pop接受缓冲区中的包大小,如果错误直接清除缓冲区(主要针对服务器攻击)
4.安全检测,在当服务器发现错误的数据包类型踢出连接(2,3情况下判断),数据收发超过一定时间也可以踢出.
如果要同时多次异步发送,就是把数据分割到每个per_io_buffer_size发送,但不推荐使用.

119

主题

1367

帖子

1393

积分

金牌会员

Rank: 6Rank: 6

积分
1393
 楼主| 发表于 2007-10-29 15:32:00 | 显示全部楼层

Re:tcp中拼包,拆包,粘包,这些问题怎么处理??

我已经搞定了。
我进入了一个误区,发送数据的时候不需要考虑per_io_buffer_size,也就是WSABUF直接指向你要发送的数据,并设置它的len就可以了,如果发送的时候还吧per_io_buffer_size定死的话,那可麻烦了,得要把数据给拆成一个个的定长的buffer再发,多此一举

bool IocpService::SendOut(LPPER_IO_DATA lpPer_io_data, const char *data, const int length)
{
    Sleep(10); //如果连着发送多个小包,那么需要sleep一下,否则投递不出去
       
        if(!lpPer_io_data) //如果session为空,表示要传递给所有的连出去的io
        {

                for(UINT i =0; i < m_io_pool_out._used_particle_vector.size(); i ++)
                {
             PER_IO_DATA * PerIoData = m_io_pool_out._used_particle_vector;
                         //PerIoData->wDataBuf.len = NET_DATA_LONGTH;    //发送的时候这里不要写死了
                         //PerIoData->wDataBuf.buf = PerIoData->dataBuf; //这里也是
                                //下面这两句就对了
                                PerIoData->wDataBuf.len = length;
                                PerIoData->wDataBuf.buf = data
                         PerIoData->dwFlags  = 0;
                         PerIoData->dwOpCode = OP_WRITE;

                         //复制要传递的数据 <---- 过去的代码,这里也不需要了
                        // memcpy(PerIoData->dataBuf, data, length);
                         
                         if(WSASend(PerIoData->socket, &amperIoData->wDataBuf, 1, &PerIoData->dwBytes,
                                 MSG_PARTIAL, &PerIoData->Overlapped, NULL) == SOCKET_ERROR)
                         {
                                 if(WSAGetLastError() != ERROR_IO_PENDING)
                                 {
                                         g_Log.Log(DEBUG_LV, "WSASend() failed with error- %d\n", WSAGetLastError());
                                         return false;
                                 }
                         }
                         SpyOutPools("SendOut() 发出数据");
                }

        }
...

这样发送的数据如果大于接受端的per_io_buffer_size,iocp会自动分几次完成事件来接受(很聪明嘛),接受端做拼包处理,就是用前面朋友的方法,在一个包的首未放入长度信息来拼包接受端拼包程序我已经写好了,并做了测试已经ok了
我的接收端是一个per_io_data它关联一个session对象,session对象里面有RevBuffer这是真正的接受完整数据包的地方。
就是粘包问题目前还没测出来,我还要进一步考虑, 这个做法也许并不严密希望不足的地方多提提意见

119

主题

1367

帖子

1393

积分

金牌会员

Rank: 6Rank: 6

积分
1393
 楼主| 发表于 2007-10-29 15:35:00 | 显示全部楼层

Re:tcp中拼包,拆包,粘包,这些问题怎么处理??

看来这里有经验并且热心的朋友真的很多,真的非常感谢大家。由衷的感谢。。。
有问题的话,我回头再继续提出来。

89

主题

822

帖子

847

积分

高级会员

Rank: 4

积分
847
发表于 2007-10-29 16:10:00 | 显示全部楼层

Re: tcp中拼包,拆包,粘包,这些问题怎么处理??

Sleep(10); //如果连着发送多个小包,那么需要sleep一下,否则投递不出去


没这回事

12

主题

88

帖子

133

积分

注册会员

Rank: 2

积分
133
发表于 2007-10-29 16:29:00 | 显示全部楼层

Re:tcp中拼包,拆包,粘包,这些问题怎么处理??

1.sleep(10)完全没必要,导致发送缓冲区满你就应该找你逻辑问题了.
2.没有必要把要发送的数据排队,逻辑处理时候直接send就可以了.

6

主题

471

帖子

1047

积分

金牌会员

Rank: 6Rank: 6

积分
1047
发表于 2007-10-29 17:40:00 | 显示全部楼层

Re: Re:tcp中拼包,拆包,粘包,这些问题怎么处理??

tonykee: Re:tcp中拼包,拆包,粘包,这些问题怎么处理??

我已经搞定了。
我进入了一个误区,发送数据的时候不需要考虑per_io_buffer_size,也就是WSABUF直接指向你要...

你原来的做法没错,数据是要复制到PerIoData->dataBuf中,用wsabuf指向databuf.
wsasend是异步发送,通常情况发完是很快.
但如果超时,发送还没结束,其他逻辑线程的代码进入下面2种out段,那PerIoData中的wsabuf指向的数据就会有问题.
PerIoData->dataBuf在初始的时候可以直接分配固定大小,
避免频繁newdelete造成的效能降低和内存碎片.
1.
// in
char* lpData = new char[];
SendOut(lpData)
delete lpData;
// out
2.
// in
void proc()
{
   char  buffer[];
   SendOut(buffer)   
}
// .. out
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-5-15 05:07

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表