为什么收到的TCP数据会丢包?(有代码)

gzz100 2006-03-17 10:50:03
我做的是一个转发服务:

客户端的发送SOCKET:
TCP_NODELAY关闭 ,不采用延时算法 ,立即发送

接收SOCKET也做了粘包的处理

转发服务端的用的IOCP
SOCKET的RCVBUF设为了0,因为客户端发送的数据短而多,发送的非常快
转发SOCKET也是TCP_NODELAY关闭 ,不采用延时算法 ,立即发送

服务端接受线程如下:
DWORD WINAPI ServerWorkerThread(LPVOID ComlpetionPortID)
{
CListBox* m_info=(CListBox*)ComlpetionPortID;
DWORD Recvl;
DWORD Flags;
DWORD l;
LPMHandel rsock;
LPIODATA ol;
WSABUF DATABuf;
char Buffer[TCPBUFSIZE];
DATABuf.len =TCPBUFSIZE;
DATABuf.buf=Buffer;
while (TRUE)
{
if(!GetQueuedCompletionStatus(CompetionPort,&Recvl,(LPDWORD)&rsock,(LPOVERLAPPED*)&ol,INFINITE))
{
m_info->AddString("用户异常退出");
}
if(Recvl==0) //OnClose
{
m_info->AddString("用户断开");
closesocket(rsock->sock);
Vip[rsock->last]=NULL;
UDP[rsock->last-2]=NULL;
continue;
}
ZeroMemory(&(ol->OVerlapped),sizeof(OVERLAPPED));
Flags=0;
WSARecv(rsock->sock,&DATABuf,1,&l,&Flags,&(ol->OVerlapped),NULL);
head temp;
int a;
memcpy(&temp,Buffer,12);
if(temp.pro==103)
{
temp.pro=122;
temp.vip=rsock->vip;
send(rsock->sock,(char*)&temp,12,0);
}else{
a=temp.vip>>24;
send(Vip[a],Buffer,Recvl,0);
}
l=0;
ZeroMemory(Buffer,sizeof(Buffer));
}
}

我发现当客户端数据发送的频率很高时,服务端就会有包没发出去(也可能是没收到),这是什么原因啊??我刚学IOCP,向大家请教一下高效率的IOCP怎么实现?
...全文
443 7 打赏 收藏 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
KDE 2006-03-24
  • 打赏
  • 举报
回复
学习。
Pasp 2006-03-24
  • 打赏
  • 举报
回复
建议使用开源的Indy控件,封装的比较好,用起来方便,适合快速开发
yangang 2006-03-21
  • 打赏
  • 举报
回复
学习 mmark
yz20050510 2006-03-21
  • 打赏
  • 举报
回复
我同意楼上的看法,你发送的频率抬高时,服务器很有可能不能及时处理,出现丢包现象,可以换种思路开发
pp616 2006-03-20
  • 打赏
  • 举报
回复
看了下代码楼主的代码流程是这样的
查询完成端口->如果有连接断开做断开的处理->投递接收操作->处理数据(已阻塞方式转发数据)->清空接收缓冲

问题1:为什么要在数据处理前再次投递接收操作?如果是多服务线程的话。有可能出现第一次来的数据还没处理完第二的数据就到了。那就是说一个线程还没来急处理Buffer里的内容一个线程又将Buffer中的内容改写那样的话到底处理的是什么数据?

问题2:
DATABuf.len =TCPBUFSIZE;
.....
WSARecv(rsock->sock,&DATABuf,1,&l,&Flags,&(ol->OVerlapped),NULL);
代码当投递了接收操作后GetQueuedCompletionStatus函数返回时,到底收到多少数据在Recvl里体现。楼主没对Recvl进行判断。直接就进行了数据处理,这样可能会出现:数据包还未接收完整时就进行处理,或是N个包粘在了一起但是只做了一次处理。

问题3:
既然用了iocp模式为什么还要用阻塞的方式发送数据。那样当send操作未返回的时候整个服务线程就阻塞了。大大的降低了服务线程的效率。

我建立的解决方法
1。等数据处理完再投递下一个接收操作

2。判断Recvl。如果数据不完整继续投递接收操作,这是的DATABuf.buf应该为DATABuf.buf+Recvl。如果Recvl大于希望一次处理的数据量那就分次处理。
还可以把希望接收的长度写在LPIODATA结构中。当收到的数据长度=希望长度时再进行处理。<就继续接收。

3。发送数据也应该使用iocp方式投递完发送操作后立即继续接收下个数据包。不要去等待send函数返回。如果一定要用阻塞方式发送可以构造一个数据队列,开个线程从队列中取数据发送。当收到适量的数据后把数据放到数据队列里,继续进行下一次的接收操作。

这是我的理解说的可能不对,有错的地方还请哥们们指出。
「已注销」 2006-03-20
  • 打赏
  • 举报
回复
说说你的思路吧
huzhangyou 2006-03-17
  • 打赏
  • 举报
回复
使用异步通讯吧 呵呵

1,317

社区成员

发帖
与我相关
我的任务
社区描述
C++ Builder 网络及通讯开发
社区管理员
  • 网络及通讯开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧