设置connect()函数的超时时间c中的tcp套接字编程中断recv()
在我的程序中如果无法访问服务器,则连接function会花费太多时间。 所以我尝试使用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; }
设置connect()函数的超时时间C中的tcp套接字编程不起作用
更正。 设置连接超时正在运行。 什么’不工作’是后续的recvfrom()
,这是因为你以非阻塞模式离开套接字而你不知道如何处理生成的EAGAIN.
因此,要么处理它,通过使用select()
告诉您套接字何时准备好读取,或者在完成连接后将套接字重新置于阻塞模式。
第一次成功选择意味着连接操作已完成但并不一定意味着它成功 ,从连接手册页,您应该检查SO_ERROR
以确保它成功完成
通过选择用于写入的套接字,可以选择(2)或轮询(2)以完成。 在select(2)指示可写性之后,使用getsockopt(2)读取SOL_SOCKET级别的SO_ERROR选项以确定connect()是否成功完成 (SO_ERROR为零)或失败(SO_ERROR是此处列出的常见错误代码之一,解释了失败的原因)。
所以在你的代码中你应该做这样的事情:
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 }
然后,如在另一个答案中所提到的,您应该在写入或从套接字读取之前再次调用select。
您收到EAGAIN
因为没有数据可以从套接字缓冲区读取,并且您的套接字被设置为nonblocking
。 由于你没有与同伴联系,我对此并不感到惊讶。
从man recvfrom
看这个:
如果套接字上没有可用的消息,则接收调用等待消息到达,除非套接字是非阻塞的(请参阅fcntl(2)),在这种情况下返回值-1并将外部变量errno设置为EAGAIN。 接收呼叫通常会返回任何可用的数据,直到请求的数量,而不是等待收到所请求的全部金额。
另一个案例可能如下:
- 您的sockets可能已连接,但是如果收到某些内容,则检查太快。 为避免这种情况,请在recvfrom之前添加另一个select,以便仅在您确定收到某些内容时从套接字缓冲区中提取数据包(调用
readfrom
或只read
)。
在调用recv()之前,应该再次将套接字设置为阻塞模式。
fcntl(sockfd, F_SETFL, fcntl(sockfd, F_GETFL, 0) & ~O_NONBLOCK);