这样用select,丢失数据,怎么解决?

shan_dong_ren 2009-09-03 12:31:58
我分析了一下原因,可能是因为存stcp2的数据的时候,因为时间耗费太长,所以造成stcp1接收到的数据没有得到及时的保存,所以会有数据丢失,这个问题怎么解决呢?小弟想了好久,也测试好久,都没能克服,还请高人指点一下,谢谢
while(1)
{
FD_ZERO(&recvSet);
FD_SET(stcp1,&recvSet);
FD_SET(stcp2,&recvSet);

ret=select(0,&recvSet,NULL,NULL,&tv) ;

if(stcp1,&recvSet)
{
//如果stcp1有数据需要读入,将数据存入链表
}

if(stcp2,&recvSet)
{
//如果stcp2有数据需要读入,将数据存入链表
}
}
...全文
493 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
shan_dong_ren 2009-09-04
  • 打赏
  • 举报
回复
呵呵,你也是山东人啊,缘分~~,握个手,俺是山东济宁的

第一次还有人夸我代码风格好,汗颜啊,不敢当,小弟没系统学过C++,VC,半路出家,哪里谈的上什么风格噢

回复1、我恰恰觉得我现在的情况是第一次的数据还没采集完,第二次的又来了,所以会有问题。select返回值为0,只是我照书上写的,想想你的说,也有些道理
回复2、修改后的程序我已经加锁了,但是还是没有什么实质性的进展。
lbjfeng 2009-09-04
  • 打赏
  • 举报
回复
[Quote=引用 16 楼 lbjfeng 的回复:]
提出两点:
1.当select的返回值为0的时候,不应该取消掉。因为只是超时,很可能数据还没有发过来。只凭借这个就是取消·~似乎。当然,lz可能有自己的用途

2.没有看到你保存socket第二种连接的相关代码。不过,感觉是一点,应该分别是两个线程,分别对应第一胎设备socket的接受,第二台设备socket的接受。接收到以后方知道链表中·~
但是,对同一个链表进行写,你却没有设置临界区。可能会造成脏数据。
所以,建议你用临界区。

InitializeCriticalSection
然后每次进入加锁。。。

3.兄弟你也是山东的??呵呵,缘分啊

4.兄弟你的代码写的挺好,风格。但是貌似对与多线程了解的还不深·~当然,小弟也不深
[/Quote]
应该是四点。
不过,有用的,只有两点,呵呵
lbjfeng 2009-09-04
  • 打赏
  • 举报
回复
提出两点:
1.当select的返回值为0的时候,不应该取消掉。因为只是超时,很可能数据还没有发过来。只凭借这个就是取消·~似乎。当然,lz可能有自己的用途

2.没有看到你保存socket第二种连接的相关代码。不过,感觉是一点,应该分别是两个线程,分别对应第一胎设备socket的接受,第二台设备socket的接受。接收到以后方知道链表中·~
但是,对同一个链表进行写,你却没有设置临界区。可能会造成脏数据。
所以,建议你用临界区。

InitializeCriticalSection
然后每次进入加锁。。。

3.兄弟你也是山东的??呵呵,缘分啊

4.兄弟你的代码写的挺好,风格。但是貌似对与多线程了解的还不深·~当然,小弟也不深
xylicon 2009-09-03
  • 打赏
  • 举报
回复
while(1)
{
FD_ZERO(&recvSet);
FD_SET(stcp1,&recvSet);
FD_SET(stcp2,&recvSet);

ret=select(0,&recvSet,NULL,NULL,&tv) ;

if(stcp1,&recvSet) {
//如果stcp1有数据需要读入,将数据存入链表
}

if(stcp2,&recvSet) {
//如果stcp2有数据需要读入,将数据存入链表
}
}

应该改成
while(1)
{
FD_ZERO(&recvSet);
FD_SET(stcp1,&recvSet);
FD_SET(stcp2,&recvSet);

ret=select(0,&recvSet,NULL,NULL,&tv) ;

if(FD_ISSET(stcp1,&recvSet))
{
//如果stcp1有数据需要读入,将数据存入链表
}

if(FD_ISSET(stcp2,&recvSet))
{
//如果stcp2有数据需要读入,将数据存入链表
}
}
iamcarter10000 2009-09-03
  • 打赏
  • 举报
回复
这个看起来不错……
ilovebj0818 2009-09-03
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 shan_dong_ren 的回复:]
//1#监测仪保存至链表线程
C/C++ codeUINT StoreToList1(LPVOID pParam)
{
UINT i;
UINT j;int cnt;
UINT recvTime1;
UINT recvChannel1;
UINT recvDatalen1;int precvbuf1[16384*4];while(1)
{
WaitForSingleObject(EventStoreToList1, INFINITE);//等待EventStore有信号//接收时间 i=0;while( i<8)
{
cnt= recv( stcpactive[MonitorOfIP[0]], (char*)&recvTime1+i,8-i,0 );if( cnt<=0)
{
AfxMessageBox("recv failed5");
}

i+= cnt;//创建链表 pNewData1=new RecvData;//链表新节点if( i==8)
{
pNewData1->recvtime= recvTime1;//将接收到的时间放入链表 }
}//接收通道号 i=0;while( i<4)
{
cnt= recv( stcpactive[MonitorOfIP[0]], (char*)&recvChannel1+i,4-i,0 );if( cnt<=0)
{
AfxMessageBox("recv failed6");
}

i+= cnt;if( i==4)
{
pNewData1->channelID= recvChannel1;//将接收到的通道号放入链表 }
}//接收数据长度 i=0;while( i<4)
{
cnt= recv( stcpactive[MonitorOfIP[0]], (char*)&recvDatalen1+i,4-i,0 );if( cnt<=0)
{
AfxMessageBox("recv failed7");
}

i+= cnt;if( i==4)
{
pNewData1->recvdatalen= recvDatalen1;//将接收到的数据长度放入链表 }
}//接收数据 i=0;while( i< recvDatalen1*4)
{
cnt= recv( stcpactive[MonitorOfIP[0]], (char*)precvbuf1+i, recvDatalen1*4-i,0 );if( cnt<=0)
{
AfxMessageBox("recv failed8");
}

i+= cnt;
}if( i== recvDatalen1*4)
{for( j=0; j<recvDatalen1*4; j++)
{*(pNewData1->recvbuffer+j)=*(precvbuf1+j);
}
}//链表后续处理if(phead1==NULL)//若为首节点 {
phead1=pNewData1;
pEnd1=pNewData1;
}else//若不为首节点 {
pEnd1->next=pNewData1;
pEnd1=pNewData1;
}

EventStoreMonitor1.SetEvent();//设置 EventStore有信号
}return0;
}
[/Quote]
shan_dong_ren 2009-09-03
  • 打赏
  • 举报
回复
另外线程基本和上面这个线程一样

//2#监测仪保存至链表线程
UINT StoreToList2(LPVOID pParam)
{
}
shan_dong_ren 2009-09-03
  • 打赏
  • 举报
回复
//1#监测仪保存至链表线程
UINT StoreToList1(LPVOID pParam)
{
UINT i;
UINT j;
int cnt;
UINT recvTime1;
UINT recvChannel1;
UINT recvDatalen1;
int precvbuf1[16384*4];

while(1)
{
WaitForSingleObject(EventStoreToList1, INFINITE); //等待EventStore有信号
//接收时间
i = 0;
while( i < 8)
{
cnt = recv( stcpactive[MonitorOfIP[0]], (char*)&recvTime1+i, 8-i, 0 );
if( cnt <=0)
{
AfxMessageBox("recv failed5");
}

i += cnt;
//创建链表
pNewData1=new RecvData;//链表新节点

if( i == 8)
{
pNewData1->recvtime = recvTime1;//将接收到的时间放入链表
}
}
//接收通道号
i = 0;
while( i < 4)
{
cnt = recv( stcpactive[MonitorOfIP[0]], (char*)&recvChannel1+i, 4-i, 0 );
if( cnt <=0)
{
AfxMessageBox("recv failed6");
}

i += cnt;

if( i == 4)
{
pNewData1->channelID = recvChannel1;//将接收到的通道号放入链表
}
}
//接收数据长度
i = 0;
while( i < 4)
{
cnt = recv( stcpactive[MonitorOfIP[0]], (char*)&recvDatalen1+i, 4-i, 0 );
if( cnt <=0)
{
AfxMessageBox("recv failed7");
}

i += cnt;

if( i == 4)
{
pNewData1->recvdatalen = recvDatalen1;//将接收到的数据长度放入链表
}
}
//接收数据
i = 0;
while( i < recvDatalen1*4)
{
cnt = recv( stcpactive[MonitorOfIP[0]], (char*)precvbuf1+i, recvDatalen1*4-i, 0 );
if( cnt <=0)
{
AfxMessageBox("recv failed8");
}

i += cnt;
}

if( i == recvDatalen1*4)
{
for( j=0; j<recvDatalen1*4; j++)
{
*(pNewData1->recvbuffer+j) = *(precvbuf1+j);
}
}

//链表后续处理
if(phead1==NULL)//若为首节点
{
phead1=pNewData1;
pEnd1=pNewData1;
}
else//若不为首节点
{
pEnd1->next=pNewData1;
pEnd1=pNewData1;
}

EventStoreMonitor1.SetEvent();//设置 EventStore有信号

}
return 0;
}
shan_dong_ren 2009-09-03
  • 打赏
  • 举报
回复
按楼上的建议改了,但不知为什么每次接收都跳出来
recv failed1
。。。。。。。
recv failed8

贴出代码,让大家看看哪里的问题

定义两个全局的套接口用于接收数据
SOCKET stcpactive[2];

接收线程
UINT Recvdata(LPVOID pParam)
{
//开始接接收数据
while(1)
{
//select 操作
FD_ZERO(&recvSet);

for(i=0;i<2;i++)
{
FD_SET(stcpactive[i],&recvSet);
}

ret=select(0,&recvSet,NULL,NULL,&tv);//等待100ms

//case 1:select error

if(ret==SOCKET_ERROR)
{
::AfxMessageBox ("select error");
goto leave;
}

//case 2:select timeout

if(ret==0)
{
goto leave;
}

//case 3:select
for(int m=0;m<2;m++)
{
//判断是1#监测仪

if(FD_ISSET(stcpactive[m],&recvSet))//如果1#监测仪有信号
{
MonitorOfIP[0]=m;
EventStoreToList1.SetEvent();//启动保存至链表线程

}
}
//判断是2监测仪


if(FD_ISSET(stcpactive[m],&recvSet))
{
MonitorOfIP[1]=m;
EventStoreToList2.SetEvent
}

}

}

}

leave:
// We only get here on an error - close the sockets
if( stcp >= 0 )
{
closesocket(stcp);
}


WSACleanup();

goto TrgRecvRestart;

return 0;
}
iamwjp 2009-09-03
  • 打赏
  • 举报
回复
每一个连接用一个独立的线程进行接收
shan_dong_ren 2009-09-03
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 conry 的回复:]
又是tcp粘包问题

[/Quote]
是啊,单台仪器的时候我用链表结构解决了,现在多台的,不知该怎么办了,请高人指点一下
Conry 2009-09-03
  • 打赏
  • 举报
回复
又是tcp粘包问题
shan_dong_ren 2009-09-03
  • 打赏
  • 举报
回复
我这个问题很奇怪吗?
shan_dong_ren 2009-09-03
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 lbjfeng 的回复:]
你确定是数据被丢失了???

我感觉你推断的原因站不住脚

是不是第一次select还没有接完,这个是有可能的·~或许,它会继续出发select
[/Quote]

“第一次select还没有接完,这个是有可能的”
应该不是,因为数据的丢失是在两帧数据之间,第一帧数据已经接收完了
stjay 2009-09-03
  • 打赏
  • 举报
回复
stcp1,stcp2其中一个处理数据的时间过长
应该只会造成对应的客户端send超时
而不会recv到的数据丢失

用多线程可以改善一下么...
shan_dong_ren 2009-09-03
  • 打赏
  • 举报
回复
我两个是接收的同样的数据,测试都是用的正弦波,但是两个保存的都有数据丢失
lbjfeng 2009-09-03
  • 打赏
  • 举报
回复
你确定是数据被丢失了???

我感觉你推断的原因站不住脚

是不是第一次select还没有接完,这个是有可能的·~或许,它会继续出发select
shan_dong_ren 2009-09-03
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 xylicon 的回复:]
while(1)
{
      FD_ZERO(&recvSet);
      FD_SET(stcp1,&recvSet);
      FD_SET(stcp2,&recvSet);

      ret=select(0,&recvSet,NULL,NULL,&tv) ;

     if(stcp1,&recvSet)      {
        //如果stcp1有数据需要读入,将数据存入链表
      }

     if(stcp2,&recvSet)      {
        //如果stcp2有数据需要读入,将数据存入链表
      }
}

应该改成
C/C++ codewhile(1)
{
FD_ZERO(&recvSet);
FD_SET(stcp1,&recvSet);
FD_SET(stcp2,&recvSet);

ret=select(0,&recvSet,NULL,NULL,&tv) ;if(FD_ISSET(stcp1,&recvSet))
{//如果stcp1有数据需要读入,将数据存入链表 }if(FD_ISSET(stcp2,&recvSet))
{//如果stcp2有数据需要读入,将数据存入链表 }
}
[/Quote]

不好意思,敲错了,但那不是原因啊

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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