为什么在设置SO_RCVTIMEO时recv返回-1并且errno = EINTR?

时间:2018-08-03 06:08:46

标签: c++ linux recv setsockopt

仅当使用SO_RCVTIMEO设置套接字超时时,才会出现此问题。

recv应该阻塞3秒。但是由于另一个线程启动,它会由于EINTR而返回。

如果我运行线程t2,则线程recv中的t1将返回-1而不会阻塞,并将errno设置为EINTR

但是,当线程recv未启动时,线程t1中的t2可以正常工作,仅阻塞3秒钟。

如果线程t2在线程t1之前运行,则recv也可以正常工作。

我发现每次使用SlickEdit或gdb进行调试时,它都会失败。但是在终端中运行时可以正常工作。

这是代码:

test.cpp:链接-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();
}

2 个答案:

答案 0 :(得分:1)

这是一个潜在的错误

bzero(&(server_addr.sin_zero),8);

应该是

bzero(&(server_addr.sin_zero), sizeof(server_addr.sin_zero));

添加信号处理程序以找出错误所在,对于linux,有一种方法可以处理所有example

答案 1 :(得分:0)

请参阅“一些程序员老兄”对EINTR的评论

除非可以异步设置/修改断点,否则调试器(gdb)需要停止目标(您的任务),设置断点,然后恢复它。 要停止它,它可能会发送SIGINT,这将导致系统上的EINTR被阻止。

如果您使用GNU C库,则可以使用TEMP_FAILURE_RETRY宏,请参阅以下文章: TEMP_FAILURE_RETRY and __USE_GNU