【问题标题】:Set timeout for winsock recvfrom为winsock recvfrom设置超时
【发布时间】:2010-12-21 22:06:19
【问题描述】:

我正在尝试将阻塞套接字设置为在端口上尝试 recvfrom() 16 毫秒后超时。平台是Windows。我在网上看了很多例子,看起来很简单,我似乎无法让它工作。任何帮助将不胜感激!

#include <winsock2.h>
#include <string>

#pragma comment(lib, "ws2_32.lib")

#define PORT_NUM 8001

int main(void)
{
  std::string localIP;
  sockaddr_in localAddr;
  sockaddr_in remoteAddr;
  hostent* localhost;
  char buffer[1024];
  WSADATA wsData;

  int result = WSAStartup(MAKEWORD(2,2), &wsData);  // winsock version 2

  localhost = gethostbyname("");
  localIP   = inet_ntoa(*(in_addr*)*localhost->h_addr_list);

  localAddr.sin_family       = AF_INET;
  localAddr.sin_port         = htons(PORT_NUM);             // Set Port Number
  localAddr.sin_addr.s_addr  = inet_addr(localIP.c_str());  // Set IP Address

  int mHandle = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, 0);

  if(mHandle == INVALID_SOCKET)
    return 1;


  if(bind(mHandle, (SOCKADDR*)&localAddr, sizeof(localAddr)) == SOCKET_ERROR)
    return 1;

  timeval tv;
  tv.tv_sec  = 0;
  tv.tv_usec = 1600;

    // Set Timeout for recv call
  if(setsockopt(mHandle, SOL_SOCKET, SO_RCVTIMEO, 
                reinterpret_cast<char*>(&tv), sizeof(timeval)))
    return 1;

  int length = sizeof(remoteAddr);

  // <-- Blocks here forever
  recvfrom(mHandle, buffer, 1024, 0, (SOCKADDR*)&remoteAddr, &length);  

  return 0;
}

/*  I've also tried passing the time like so:
int ms = 16;

if(setsockopt(mHandle, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast<char*>(&ms), sizeof(int)))
  return 1; */

【问题讨论】:

  • SO_RCVTIMEO 不是很便携 - 您使用的是什么平台?
  • 你可能想使用select函数
  • 嘿,谢谢!是的,我研究了 select 并让它工作!
  • 未来读者请注意:1600 微秒不等于 16 毫秒。
  • Window 的 winsoc2 文档指出 SO_RCVTIMEO 是一个 DWORD,以毫秒为单位。科里的最后一次尝试是正确的。我不确定为什么它不起作用,也许是 reinterpret_cast。相反,使用... (const char *)&ms。

标签: c networking sockets network-programming


【解决方案1】:

我查看了 select 函数,正如 laura 所说我应该做的那样,让它真正轻松地工作!谢谢!

fd_set fds ;
int n ;
struct timeval tv ;

// Set up the file descriptor set.
FD_ZERO(&fds) ;
FD_SET(mHandle, &fds) ;

// Set up the struct timeval for the timeout.
tv.tv_sec = 10 ;
tv.tv_usec = 0 ;

// Wait until timeout or data received.
n = select ( mHandle, &fds, NULL, NULL, &tv ) ;
if ( n == 0)
{ 
  printf("Timeout..\n");
  return 0 ;
}
else if( n == -1 )
{
  printf("Error..\n");
  return 1;   
}

int length = sizeof(remoteAddr);

recvfrom(mHandle, buffer, 1024, 0, (SOCKADDR*)&remoteAddr, &length); 

【讨论】:

  • 所以我理解你每次运行应用程序时只发送一个数据包。假设您在循环中发送数千个数据包,此代码可能会崩溃!你将如何解决这个问题?
  • 这是最好的答案。另一个答案 - SO_RCVTIMEO 作为 DWORD - 将使 recvfrom 超时,但它有一些问题:1)如果发生超时,套接字不再处于有效状态。 2)我找不到任何解释如何关闭超时的 Windows 文档...但是由于您的套接字将失效,我想您无论如何都必须制作一个新的。
【解决方案2】:

我尝试过像下面这样传递它

     int iTimeout = 1600;
     iRet = setsockopt( pSapManager->m_cSocket,
                        SOL_SOCKET,
                        SO_RCVTIMEO,
                        /*
                        reinterpret_cast<char*>(&tv),
                        sizeof(timeval) );
                        */
                        (const char *)&iTimeout,
                        sizeof(iTimeout) );

并运行它!

【讨论】:

  • 嗨,欢迎来到 SO。请尝试用文字来解释您的答案,而不仅仅是代码。每个人都会更容易学习这种方式。另外,由于您正在回答一个老问题,您的答案与其他答案有何不同?
  • 来自文档:The level at which the option is defined (for example, SOL_SOCKET).SO_RCVTIMEO DWORD Sets the timeout, in milliseconds, for blocking receive calls.
【解决方案3】:

窗口: 超时值是以毫秒为单位的 DWORD,传递给 setsockopt() 的地址是 const char *

Linux: 超时值为 struct timeval,传递给 setsockopt() 的地址为 const void *

来源:http://forums.codeguru.com/showthread.php?t=353217

【讨论】:

    【解决方案4】:

    我从 WSASocket() 调用中猜测 Windows。如果是这样,您错误地通过了超时。

    MSDN 表示 SO_RCVTIMEO 采用一个 int 参数,以毫秒为单位指定超时。

    【讨论】:

    • 我也尝试过传递它,如下所示:int ms = 16; if(setsockopt(mHandle, SOL_SOCKET, SO_RCVTIMEO, reinterpret_cast(&ms), sizeof(int))) 返回 1;我仍然有相同的结果..
    • 谢谢,这正是我不接受 SO_RCVTIMEO 的 BSD 套接字系统所需要的
    • 它还说“如果阻塞接收调用超时,则连接处于不确定状态并应关闭。如果使用 WSASocket 函数创建套接字,则 dwFlags 参数必须具有 WSA_FLAG_OVERLAPPED属性设置为超时正常运行。否则超时永远不会生效。”,所以我不确定它是否会定期使用......
    • 查看此页面:msdn.microsoft.com/en-gb/library/windows/desktop/… 我没有看到 WSA_FLAG_OVERLAPPED 的提及(对于重叠的套接字通过 SO_RCVTIMEO 设置接收超时对我来说真的没有意义跨度>
    猜你喜欢
    • 2012-06-14
    • 1970-01-01
    • 1970-01-01
    • 2020-11-12
    • 1970-01-01
    • 2021-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多