为什么在设置 SO_RCVTIMEO 时 recv returns -1 和 errno=EINTR?
Why recv returns -1 and errno=EINTR when set SO_RCVTIMEO?
此问题仅在套接字设置超时时发生SO_RCVTIMEO。
recv
应该阻塞 3 秒。但它 return 是因为 EINTR 一旦另一个线程启动。
如果我 运行 线程 t2
,线程 t1
中的 recv
将 return -1
不阻塞并设置 errno
到 EINTR
.
但是线程t1
中的recv
在线程t2
未启动时正常运行,它只是阻塞了3秒。
如果线程 t2
运行 早于线程 t1
,recv
也能正常工作。
我用SlickEdit 或gdb 调试时发现每次都失败。但是当它 运行 在终端中时可以正常工作。
代码如下:
test.cpp: link -pthread
使用 <thread>
或线程抛出异常
#include<unistd.h>
#include<netdb.h>
#include<string.h>
#include<thread>
int socket_fd;
sockaddr_in server_addr;
void recvThread()
{
char pData[4096];
int len = recv(socket_fd,pData,4096,0);
if(len<=0)
{
printf("len:%d\n",len);
printf("errno:%d\n",errno);
}
}
void otherThread()
{
while(1)
{
sleep(1);
}
}
int main()
{
hostent *host;
if((host=gethostbyname("127.0.0.1"))==NULL)
{
return 1;
}
memset(&server_addr, 0, sizeof(sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(8887);
server_addr.sin_addr=*((in_addr*)host->h_addr);
bzero(&(server_addr.sin_zero),8);
socket_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
timeval timeout = {3,0};
setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeval));
if(connect(socket_fd, (sockaddr*)&server_addr, sizeof(server_addr))<0)
{
return 1;
}
std::thread t1(recvThread);
std::thread t2(otherThread);
t1.join();
t2.join();
}
这是一个潜在的错误
bzero(&(server_addr.sin_zero),8);
应该是
bzero(&(server_addr.sin_zero), sizeof(server_addr.sin_zero));
为 linux there is a method to handle all, example 添加信号处理程序以查明错误是什么。
请参阅 "Some programmer dude"
对 EINTR 的评论
调试器 (gdb),除非可以 set/modify 异步断点,否则需要停止目标(您的任务),设置断点,然后恢复它。
要停止它,它可以发送 SIGINT,这将导致系统上的 EINTR 阻塞调用。
如果您使用 GNU C 库,您可以使用 TEMP_FAILURE_RETRY 宏,请参阅此 post:
TEMP_FAILURE_RETRY and __USE_GNU
此问题仅在套接字设置超时时发生SO_RCVTIMEO。
recv
应该阻塞 3 秒。但它 return 是因为 EINTR 一旦另一个线程启动。
如果我 运行 线程 t2
,线程 t1
中的 recv
将 return -1
不阻塞并设置 errno
到 EINTR
.
但是线程t1
中的recv
在线程t2
未启动时正常运行,它只是阻塞了3秒。
如果线程 t2
运行 早于线程 t1
,recv
也能正常工作。
我用SlickEdit 或gdb 调试时发现每次都失败。但是当它 运行 在终端中时可以正常工作。
代码如下:
test.cpp: link -pthread
使用 <thread>
或线程抛出异常
#include<unistd.h>
#include<netdb.h>
#include<string.h>
#include<thread>
int socket_fd;
sockaddr_in server_addr;
void recvThread()
{
char pData[4096];
int len = recv(socket_fd,pData,4096,0);
if(len<=0)
{
printf("len:%d\n",len);
printf("errno:%d\n",errno);
}
}
void otherThread()
{
while(1)
{
sleep(1);
}
}
int main()
{
hostent *host;
if((host=gethostbyname("127.0.0.1"))==NULL)
{
return 1;
}
memset(&server_addr, 0, sizeof(sockaddr_in));
server_addr.sin_family=AF_INET;
server_addr.sin_port=htons(8887);
server_addr.sin_addr=*((in_addr*)host->h_addr);
bzero(&(server_addr.sin_zero),8);
socket_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
timeval timeout = {3,0};
setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeval));
if(connect(socket_fd, (sockaddr*)&server_addr, sizeof(server_addr))<0)
{
return 1;
}
std::thread t1(recvThread);
std::thread t2(otherThread);
t1.join();
t2.join();
}
这是一个潜在的错误
bzero(&(server_addr.sin_zero),8);
应该是
bzero(&(server_addr.sin_zero), sizeof(server_addr.sin_zero));
为 linux there is a method to handle all, example 添加信号处理程序以查明错误是什么。
请参阅 "Some programmer dude"
对 EINTR 的评论调试器 (gdb),除非可以 set/modify 异步断点,否则需要停止目标(您的任务),设置断点,然后恢复它。 要停止它,它可以发送 SIGINT,这将导致系统上的 EINTR 阻塞调用。
如果您使用 GNU C 库,您可以使用 TEMP_FAILURE_RETRY 宏,请参阅此 post: TEMP_FAILURE_RETRY and __USE_GNU