【问题标题】:socket select fails with operation in progress - Non blocking mode套接字选择失败,操作正在进行 - 非阻塞模式
【发布时间】:2012-06-22 06:28:39
【问题描述】:

我们的应用程序使用非阻塞套接字使用连接和选择操作(c 代码)。 pusdo 代码如下

unsigned int ConnectToServer(struct sockaddr_in *pSelfAddr,struct sockaddr_in *pDestAddr)
{
    int sktConnect = -1;

    sktConnect = socket(AF_INET,SOCK_STREAM,0);
    if(sktConnect == INVALID_SOCKET)
        return -1;


    fcntl(sktConnect,F_SETFL,fcntl(sktConnect,F_GETFL) | O_NONBLOCK);
    if(pSelfAddr != 0)
    {
        if(bind(sktConnect,(const struct sockaddr*)(void *)pSelfAddr,sizeof(*pSelfAddr)) != 0)
        {
            closesocket(sktConnect);
            return -1;
        }
    }


    errno = 0;
    int nRc = connect(sktConnect,(const struct sockaddr*)(void *)pDestAddr, sizeof(*pDestAddr));
    if(nrC != -1)
    {
        return sktConnect;
    }

    if(errno != EINPROGRESS)
    {
        int savedError = errno;
        closesocket(sktConnect);
        return -1;
    }

    fd_set scanSet;
    FD_ZERO(&scanSet);
    FD_SET(sktConnect,&scanSet);

    struct timeval waitTime;
    waitTime.tv_sec = 2;
    waitTime.tv_usec = 0;

    int tmp;
    tmp = select(sktConnect +1, (fd_set*)0, &scanSet, (fd_set*)0,&waitTime);
    if(tmp == -1 || !FD_ISSET(sktConnect,&scanSet))
    {
        int savedErrorNo = errno;
        writeLog("Connect %s failed after select, cause %d, error %s",inet_ntoa(pDestAddr->sin_addr),savedErrorNo,strerror(savedErrorNo));
        closesocket(sktConnect);
        return -1;
    }

    .   
    .   
    .
    .
    .}  

问题陈述
在上面的代码中,select 失败,error code 115 是“正在进行的操作”。我没有看到任何关于select 的文档以errno 115 失败。

一个。 select 何时在非阻塞套接字中出现 error code 115 失败?在什么场景下?
湾。我们是否看到任何提示此问题的系统日志。只关心我 - 我找不到任何描述此类问题的文档功能。


PS:我们使用的是 SUSE Linux 11 Enterprise Edition。

【问题讨论】:

    标签: c sockets network-programming


    【解决方案1】:

    errno EINPROGRESS 不是来自 select(),它是之前的 connect() 操作遗留下来的。如果 either select() 返回 -1 FD 未设置,则输入报告它的块。这一切意味着连接仍在进行中。 errno 永远不会被清除,只会被设置。

    【讨论】:

      【解决方案2】:

      对您的代码的一些想法:

      我认为可以修改选择下方的条件以仅检查是否选择返回大于0的值,如果是这种情况,您可以检查套接字的getsockopt输出(对于SOL_SOCKET和SO_ERROR) options (getsockopt(...,SOL_SOCKET, SO_ERROR,...,...)) 查看连接是否失败。

      我不太确定如果连接成功,选择是否总是将套接字返回为可写。因此,在您的情况下,它可能(可能)是 tmp 变量不是 -1 并且它显示的 errno 是前一个连接调用的 errno。

      其他原因:

      另一个很好的理由是,您要连接的目标地址要么无法访问,要么没有服务器在指定的地址 + 端口组合处等待。在这种情况下,您可以使用阻塞套接字尝试一次以查看是否连接。

      【讨论】:

      • 调用select不会重置errno的值吗?我假设它在每次系统调用之前都会被重置。
      • 根据我的经验,我至少没有看到系统调用重置 errno。如果失败,errno 将被另一个错误覆盖。
      • select() 被定义当连接成功时返回一个可写的套接字。
      【解决方案3】:

      据我了解,您正在尝试与超时建立连接。

      如果是这样,您的代码中有错误。在connect() 调用之后但在select() 之前,您应该使用fcntl() 删除O_NONBLOCK 选项。否则select() 将始终立即返回,因为您的套接字(具有O_NONBLOCK)的操作不会阻塞。

      您阅读的 EINPROGRESS 可能不是由select() 生成的,而是由之前的connect() 调用生成的。

      您也不应该在此处使用bind() 调用,因为connect() 将您的地址隐式绑定到套接字。

      【讨论】:

      • 三个正确的陈述。关于阻塞模式的“代码错误”您错了;正确的错误;并且与绑定无关。
      猜你喜欢
      • 2018-05-18
      • 1970-01-01
      • 1970-01-01
      • 2013-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多