关于UDP的recvfrom收不到数据的问题,请高手帮忙

时刻准备中 2008-08-28 11:42:43
先把我遇到的问题部分的代码贴出来:
bool CTestSession::getNATAddress(CAddressInfo aoNATServer)
{
int iReady;
struct sockaddr_in loServAddress;
fd_set SockFd;
std::string lstrNATMsg("SHOWMENATE");
struct timeval loWaitTime = {10, 500000};
int liBytes = 0;
char lcszMsgBuf[256] = {0};
CAddressInfo loRTPNATAddress;

if (!mbIsCreated)
return false;

bzero(&loServAddress, sizeof(loServAddress));
loServAddress.sin_family = AF_INET;
loServAddress.sin_addr.s_addr = inet_addr(aoNATServer.getIP().c_str());
loServAddress.sin_port = htons(aoNATServer.getPort());

int i = 0;
lstrNATMsg += "\n";
while (!mbIsGotRTPNAT)
{
if (++i >= 100)
return false;

std::string lstrMsgType;
std::string lstrCmdBuf;

sendto(miRTPSocket, (const char *)lstrNATMsg.c_str(), lstrNATMsg.length(),
0, (const sockaddr *)&loServAddress, sizeof(loServAddress));
write_log(XFS_LOG_INFO, "send command", "send to server : %s.", lstrNATMsg.c_str());

memset(lcszMsgBuf, 0, 256);
FD_ZERO(&SockFd);
FD_SET(miRTPSocket, &SockFd);
iReady = select(miRTPSocket + 1, &SockFd, NULL, NULL, &loWaitTime);
if(iReady < 0)
{
if((errno == EAGAIN) || (errno == EINTR))
{
continue;
}
write_log(XFS_LOG_ERROR, "select", "select error : %s", strerror(errno));
}
else if (iReady == 0)
{
continue;
}

if (!FD_ISSET(miRTPSocket, &SockFd))
{
write_log(XFS_LOG_INFO, "select", "is not my sockfd.");
continue;
}

liBytes = recvfrom(miRTPSocket, lcszMsgBuf, 256, 0, NULL, NULL);
if (liBytes == -1)
write_log(XFS_LOG_INFO, "RTPSocket", "recvfrom error : %s.", strerror(errno));
if (liBytes > 0)
{
lstrCmdBuf.clear();
lstrMsgType.clear();
lstrCmdBuf += lcszMsgBuf;
std::stringstream lstrRTPStream(lstrCmdBuf);
lstrRTPStream >> lstrMsgType;
if (lstrMsgType == "SHOWMENATR")
{
loRTPNATAddress.decode(lstrRTPStream);
moNATLock.lock();
muiRTPPort = loRTPNATAddress.getPort();
moNATLock.unlock();

lstrRTPStream << loRTPNATAddress.getIP()
<< "--"
<< loRTPNATAddress.getPort();
write_log(XFS_LOG_INFO, "RTPSocket", "receive from sockfd %d : %s",
miRTPSocket, lstrRTPStream.str().c_str());

mbIsGotRTPNAT = true;
}
}
usleep(200000);
}
return true;
}

出问题的地方我用红色标示出来了,udp发送给服务器程序的消息成功,在服务器端有日志表明,而且服务器也确实给客户端程序回复了相应的消息,可是客户端有时候能收到消息,有时候收不到。如果不用select的话,recvfrom会提示Resource temporarily unavailable
。需要说明的是,这部分代码是客户端里的,服务器和客户端程序都运行在同一个机器上。而且服务器程序是肯定没问题的,因为用windows版本的客户端程序测试就不会出现问题。
这个问题都困扰兄弟我好长时间了,也搞不明白怎么回事?到底原因在哪里?select怎么就会检测不到文件描述符收到消息呢,服务器明明是回复了,windows版本的程序就一点问题都没有,Linux下的客户端程序我也是按照windows版本的移植过来的。
请高手能帮忙看一下问题可能出现在哪里?谢谢!
...全文
2357 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
时刻准备中 2008-08-29
  • 打赏
  • 举报
回复
多谢guosha,你说得对,我一直以为select不会修改参数,所以也就没有man一下看看,刚才我man了一下,发现它会修改这个时间参数。改了之后,测试了几个回合,暂时没出现问题。
时刻准备中 2008-08-29
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 guosha 的回复:]
你select的超时时间在哪里重置了?不重置的话一次以后就相当于无超时select了吧。
[/Quote]
每次循环的时候都要把超时时间重置一下啊?仅仅初始化一次不行吗?我重置一下试试
快乐田伯光 2008-08-29
  • 打赏
  • 举报
回复
你select的超时时间在哪里重置了?不重置的话一次以后就相当于无超时select了吧。
时刻准备中 2008-08-29
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 xiaoyaoyoudm 的回复:]
1.建议sendto 和select不要放在同一个循环中,因为select是有超时退出的。一旦select超时,将会倒置再发一次sendto。
2.将timeval loWaitTime = {10, 500000}; 改为timeval loWaitTime = {0, 500000}; 试试。
3.recvfrom(miRTPSocket, lcszMsgBuf, 256, 0, NULL, NULL); 为什么不用recv,因为你根本不需要from。(只是编程建议)
[/Quote]
不好意思,时间timeval loWaitTime = {10, 500000};里的10秒是我笔误,我写的是0,就是这样也不行。后来我就再将超时等待设置的大一些比如10秒,也是不行。
怎么会“监听”不到服务器回复的消息呢?服务器确实是收到请求消息也发送回复消息了。
时刻准备中 2008-08-29
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 cceczjxy 的回复:]
引用 1 楼 guosha 的回复:
每次循环的select超时时间重置一下试试。

资源临时性的不足。
这是一种方法
另外,你的程序是不是多线程的?

多线程及多进程程序中,不正确的互斥操作,也会造成这中现象的发生。
[/Quote]
我以前是用的多线程,后来查到网上说多线程会造成问题,我就改为在循环里做了,只要向服务器发送完请求就等待服务器回复消息。
lhtang 2008-08-29
  • 打赏
  • 举报
回复
建议在send后接着recvfrom(,,,MSG_PEEK,NULL,NULL)如果偷窥到消息,就马上跳到真正接收数据的地方,不过程序结构较乱,呵呵.
xiaoyaoyoudm 2008-08-29
  • 打赏
  • 举报
回复
1.建议sendto 和select不要放在同一个循环中,因为select是有超时退出的。一旦select超时,将会倒置再发一次sendto。
2.将timeval loWaitTime = {10, 500000}; 改为timeval loWaitTime = {0, 500000}; 试试。
3.recvfrom(miRTPSocket, lcszMsgBuf, 256, 0, NULL, NULL); 为什么不用recv,因为你根本不需要from。(只是编程建议)
cceczjxy 2008-08-29
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 guosha 的回复:]
每次循环的select超时时间重置一下试试。
[/Quote]
资源临时性的不足。
这是一种方法
另外,你的程序是不是多线程的?

多线程及多进程程序中,不正确的互斥操作,也会造成这中现象的发生。
快乐田伯光 2008-08-29
  • 打赏
  • 举报
回复
每次循环的select超时时间重置一下试试。
时刻准备中 2008-08-29
  • 打赏
  • 举报
回复
唉~~~是啊,确实是,我看了后感觉这个地方不应该出现问题,呵呵
快乐田伯光 2008-08-29
  • 打赏
  • 举报
回复
传引用参数进去的函数都要小心,我也犯过类似的错误。
1 楼就跟你说了这个问题了,看来你不认为是那个问题啊,呵呵

23,120

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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