织梦CMS - 轻松建站从此开始!

罗索

关于UDP socket 的10054错误解决办法

罗索客 发布于 2009-10-20 18:14 点击:次 
今天碰到了一个非常怪的问题,我的主要功能是先用UDP的Sendto发送一个数据过去,同时启动一个线程,这个线程去recvfrom来自远目地主机的包,但是每次我Sendto后,recvfrom不阻塞在那里,而报10054的错误。
TAG:

今天碰到了一个非常怪的问题,我的主要功能是先用UDP的Sendto发送一个数据过去,同时启动一个线程,这个线程去recvfrom来自远目地主机的包,但是每次我Sendto后,recvfrom不阻塞在那里,而报10054的错误。先贴代码

第一部分:主要是初始化

 WSADATA wsaData;
 WSAStartup(MAKEWORD(2,2), &wsaData);

    /*初始化服务端地址和本地客户端地址并绑定本地套接字*/

 m_nPort = GetConfigValue("BIPSERVERCONFIG", "CATPORT", 8888);//获取服务目的端口
 m_ServerAdd = GetConfigValue("BIPSERVERCONFIG" ,"CATADDRESS", "127.0.0.1");//获取服务目的端口

    m_ServerAddress.sin_family = AF_INET;
 m_ServerAddress.sin_port   = htons(m_nPort);
 m_ServerAddress.sin_addr.s_addr = inet_addr(m_ServerAdd);
 //m_ServerAddress.sin_addr.s_addr = inet_addr("10.8.4.52");

 /*设置客户端的地址*/
 m_ClientAddress.sin_family = AF_INET;
 m_ClientAddress.sin_port   = htons(0);
 m_ClientAddress.sin_addr.s_addr = htons(INADDR_ANY);

 m_ClientSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
 if(m_ClientSocket == SOCKET_ERROR)
 {
  DWORD dwError = GetLastError();
  TRACE("错误码:%d", dwError);
  WriteRunLog_EX("InitSocket","初始化套接字错误\\n");
  return FALSE;
 }


 /*将客户机的socket和客户机的Socket地址bind*/
    int ret = 0;
 ret = bind(m_ClientSocket, (struct sockaddr*)&m_ClientAddress, sizeof(m_ClientAddress));
 if (ret != 0)
    { 
  DWORD dwError = GetLastError();
  TRACE("错误码:%d", dwError);
  WriteRunLog_EX("InitSocket","bind套接字错误\\n");
  return FALSE;
    }

第二部分:Sendto处代码:从这里你可以看到,我Sendto一个包给远端目的主机马上启动一个线程去收数据。

 retCode = sendto(m_ClientSocket, lpBuf,len, 0,(struct sockaddr*)&m_ServerAddress, sizeof(m_ServerAddress));
    if (SOCKET_ERROR == retCode)
    {
  return FALSE;
    }

 ///int addressLen = sizeof(addr);
 //retCode = recvfrom(m_ClientSocket, lpBuf, len, 0, (struct sockaddr*)&addr, &addressLen );

 /*发送数据后,等待远端服务端发送数据过来*/
 pRecvThread = AfxBeginThread((AFX_THREADPROC)StartRecvProc,this,THREAD_PRIORITY_NORMAL);
 if (NULL == pRecvThread)
 { 
  TRACE("启动接收线程失败!");
  WriteRunLog_EX("StartRecv","bind错误\\n");
  return FALSE;

 }

第三部分:收线程的代码

while (TRUE)
 {
  int addressLen = sizeof(struct sockaddr);
  retCode = recvfrom(m_ClientSocket, data, sizeof(data), 0, (struct sockaddr*)&m_ServerAddress, &addressLen );
  if (SOCKET_ERROR == retCode)
  {
   DWORD dwError = GetLastError();
   TRACE("错误码为:%d",dwError);
   
   TRACE("收包错误!");
            WriteRunLog_EX("StartRecv","收包错误\\n");
  }
  else
  {
   char testBuf[8192];
   memcpy(testBuf, data, retCode);
   testBuf[retCode] = '\\0';
   TRACE("StartRecv收到包:%s",testBuf);
   BIP_CATMsg msg;
   msg.len = retCode;
   memcpy(msg.strBuf, data, msg.len);
   m_RecvMsgQueue.AddTail(msg);
  }
  
 }

我的本意在这个recvfrom处应会阻塞,但是没有,GetLastErrorr后显示10054,我在网上查了一下,原来是winsock自已的bug。具体原因是:http://support.microsoft.com/kb/263823/

If sending a datagram using the sendto function results in an "ICMP port unreachable" response and the select function is set for readfds, the program returns 1 and the subsequent call to the recvfrom function does not work with a WSAECONNRESET (10054) error response. In Microsoft Windows NT 4.0, this situation causes the select function to block or time out.

解决办法:在我第一部代码初始化后加入如下代码。

 DWORD dwBytesReturned = 0;
 BOOL bNewBehavior = FALSE;
 DWORD status;

#define SIO_UDP_CONNRESET _WSAIOW(IOC_VENDOR,12)
 // disable  new behavior using
 // IOCTL: SIO_UDP_CONNRESET
 status = WSAIoctl(m_ClientSocket, SIO_UDP_CONNRESET,
  &bNewBehavior, sizeof(bNewBehavior),
  NULL, 0, &dwBytesReturned,
  NULL, NULL);

 if (SOCKET_ERROR == status)
 {
  DWORD dwErr = WSAGetLastError();
  if (WSAEWOULDBLOCK == dwErr)
  {
   // nothing to do
   return(FALSE);
  }
  else
  {
   printf("WSAIoctl(SIO_UDP_CONNRESET) Error: %d\\n", dwErr);
   return(FALSE);
  }
 }

真是受教了,这个问题调了我好久。

(陈俊平)
本站文章除注明转载外,均为本站原创或编译欢迎任何形式的转载,但请务必注明出处,尊重他人劳动,同学习共成长。转载请注明:文章转载自:罗索实验室 [http://www.rosoo.net/a/200910/7568.html]
本文出处:CSDN.NET 作者:陈俊平
顶一下
(2)
100%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
用户名: 验证码:点击我更换图片
栏目列表
将本文分享到微信
织梦二维码生成器
推荐内容