C语言 在 C 中为 connect() 函数 tcp 套接字编程设置超时中断 recv()
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14254061/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Setting time out for connect() function tcp socket programming in C breaks recv()
提问by Rajesh
In my program If the server is not reachable the connect function take too much time. So i try to give time out to connect using select(). Now the problem is that when i try to receive data from server using recvfrom() i got error "EAGAIN". here is code used to connect and receive data from server.
在我的程序中,如果无法访问服务器,则连接功能需要花费太多时间。所以我尝试给时间来使用 select() 进行连接。现在的问题是,当我尝试使用 recvfrom() 从服务器接收数据时,出现错误“EAGAIN”。这是用于连接和从服务器接收数据的代码。
int sock;
struct sockaddr_in addr;
int connectWithServer
{
int status;
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
addr.sin_port = htons(port);
sock = socket (AF_INET,SOCK_STREAM,0);
inet_pton(AF_INET,serverIP,&addr.sin_addr);
fd_set set;
FD_ZERO(&set);
FD_SET(sock, &set);
fcntl(sock, F_SETFL, O_NONBLOCK);
if ( (status = connect(sock, (struct sockaddr*)&addr, sizeof(addr))) == -1)
{
if ( errno != EINPROGRESS )
return status;
}
status = select(sock+1, NULL, &set, NULL, &timeout);
return status;
}
long int receiveResponse (void *response , unsigned int length)
{
socklen_t sockLen = sizeof(struct sockaddr);
long int received = recvfrom(sock, response, length, 0,(struct sockaddr *)&addr, &sockLen);
printf("Received %ld bytes... err %d\n",received, errno);
return received;
}
采纳答案by user207421
Setting time out for connect() function tcp socket programming in C is not working
在 C 中为 connect() 函数 tcp 套接字编程设置超时不起作用
Correction. Setting the connect timeout isworking. What 'isn't working' is the subsequent recvfrom(), and that's because you left the socket in non-blocking mode and you don't know what to do with the resulting EAGAIN.So, either handle that, by using select()to tell you when the socket is ready to read, or else put the socket back into blocking mode after finishing the connect.
更正。设置连接超时的工作。“不工作”是后续的recvfrom(),那是因为您将套接字置于非阻塞模式并且您不知道如何EAGAIN.处理结果因此,要么处理它,要么通过使用select()告诉您套接字何时准备好读取,或者在完成连接后将套接字重新置于阻塞模式。
回答by jungwook
The socket should be set to blocking mode again before calling recv().
在调用 recv() 之前,应该将套接字再次设置为阻塞模式。
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) & ~O_NONBLOCK);
回答by Davide Berra
You receive EAGAINbecause there's no data to read from socket buffer and your socket was set as nonblocking. Since you're not connected with the peer, i'm not surprised with it.
您收到EAGAIN是因为没有要从套接字缓冲区读取的数据,并且您的套接字设置为nonblocking. 由于您没有与同行建立联系,因此我对此并不感到惊讶。
Look at this from man recvfrom:
看看这个man recvfrom:
If no messages are available at the socket, the receive calls wait for a message to arrive, unless the socket is nonblocking (see fcntl(2)), in which case the value -1 is returned and the external variable errno set to EAGAIN. The receive calls normally return any data available, up to the requested amount, rather than waiting for receipt of the full amount requested.
如果套接字上没有可用消息,则接收调用将等待消息到达,除非套接字是非阻塞的(请参阅 fcntl(2)),在这种情况下,将返回值 -1 并将外部变量 errno 设置为 EAGAIN。接收调用通常会返回任何可用的数据,最多为请求的数量,而不是等待收到请求的全部数量。
Another case could be the following:
另一种情况可能如下:
- Your socket may be connected but you're too fast checking if something is received.To avoid this, put another select before recvfrom in order to extract the packet from the socket buffer (calling
readfromor justread) only when your're sure you received something.
- 您的套接字可能已连接,但您检查是否收到某些东西的速度太快了。为避免这种情况,请在 recvfrom 之前放置另一个选择,以便仅在您确定收到某些内容时从套接字缓冲区(调用
readfrom或仅调用read)中提取数据包。
回答by iabdalkader
The first successful select means the connect operation is complete but does not necessarily mean it succeed, from connectman page, you should check SO_ERRORto make sure it completed successfully
第一次成功选择意味着连接操作完成但并不一定意味着它成功,从连接手册页,您应该检查SO_ERROR以确保它成功完成
It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully(SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).
可以通过选择用于写入的套接字来选择(2)或轮询(2)来完成。 select(2) 指示可写性后,使用getsockopt(2) 读取SOL_SOCKET 级别的SO_ERROR 选项以确定connect()是成功完成(SO_ERROR 为零)还是未成功(SO_ERROR 是此处列出的常见错误代码之一,解释了失败的原因)。
So in your code you should do something like this:
所以在你的代码中你应该做这样的事情:
int ret;
ret=select(sockfd+1, NULL, &wfds, NULL, NULL); //should use timeout
if(ret==1 && getSocketOpt(sockfd, SO_ERROR) ==0) {
return 0; //successfully connected
}
Then, as mentioned in the other answer you should call select again before writing or reading from the socket.
然后,如另一个答案中所述,您应该在从套接字写入或读取之前再次调用 select。

