Linux的TCP连接与选择()在TE​​STSERVER失败 [英] Linux TCP connect with Select() fails at testserver

查看:364
本文介绍了Linux的TCP连接与选择()在TE​​STSERVER失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题如下:
我在Linux下编程接口通过以太网来控制GPIB控制器。要做到这一点我打开一个TCP套接字,并只发送命令到控制器。这是工作的罚款至今。我在写一些我的接口单元测试都发生问题:
要检查我使用从boost的lib一个tcp受体在一个单独的线程,只是连接到它,而不是实际控制人。这是工作压力太大,但只只要从接口的connect()调用阻止。但是因为我需要为连接指定的超时()调用我不得不用select()函数连接:

My problem is the following: I'm programming an Interface in Linux to control a GPIB Controller via Ethernet. To do so I open a TCP socket and just send the commands to the Controller. This is working fine so far. The problem I have occured at writing some kind of unit test for my Interface: To check I am using a tcp acceptor from boost lib in a seperate thread and just connect to it instead of the actual controller. This is working too, but only as long as the connect() call from the interface is blocking. However since I need a specified timeout for the connect() call I had to connect with the select() function:

    // Open TCP Socket
    m_Socket = socket(PF_INET,SOCK_STREAM,0);
    if( m_Socket < 0 )
    {
        m_connectionStatus = STATUS_CLOSED;
        return ERR_NET_SOCKET;
    }

    struct sockaddr_in addr;
    inet_aton(m_Host.c_str(), &addr.sin_addr);
    addr.sin_port = htons(m_Port);
    addr.sin_family = PF_INET;

    // Set timeout values for socket
    struct timeval timeouts;
    timeouts.tv_sec = SOCKET_TIMEOUT_SEC ;   // const -> 5
    timeouts.tv_usec = SOCKET_TIMEOUT_USEC ; // const -> 0
    uint8_t optlen = sizeof(timeouts);

    if( setsockopt( m_Socket, SOL_SOCKET, SO_RCVTIMEO,&timeouts,(socklen_t)optlen) < 0 )
    {
        m_connectionStatus = STATUS_CLOSED;
        return ERR_NET_SOCKET;
    }

    // Set the Socket to TCP Nodelay ( Send immediatly after a send / write command )
    int flag_TCP_nodelay = 1;
    if ( (setsockopt( m_Socket, IPPROTO_TCP, TCP_NODELAY,
            (char *)&flag_TCP_nodelay, sizeof(flag_TCP_nodelay))) < 0)
    {
        m_connectionStatus = STATUS_CLOSED;
        return ERR_NET_SOCKET;
    }
    // Save Socket Flags
    int opts_blocking = fcntl(m_Socket, F_GETFL);
    if ( opts_blocking < 0 )
    {
        return ERR_NET_SOCKET;
    }
    int opts_noblocking = (opts_blocking | O_NONBLOCK);
    // Set Socket to Non-Blocking
    if (fcntl(m_Socket, F_SETFL, opts_noblocking)<0)
    {
        return ERR_NET_SOCKET;
    }
    // Connect
    if ( connect(m_Socket, (struct sockaddr *)&addr, sizeof(addr)) < 0)
    {
        // EINPROGRESS always appears on Non Blocking connect
        if ( errno != EINPROGRESS )
        {
            m_connectionStatus = STATUS_CLOSED;
            return ERR_NET_SOCKET;
        }
        // Create a set of sockets for select
        fd_set socks;
        FD_ZERO(&socks);
        FD_SET(m_Socket,&socks);
        // Wait for connection or timeout
        int fdcnt = select(m_Socket+1,NULL,&socks,NULL,&timeouts);
        if ( fdcnt < 0 )
        {
            return ERR_NET_SOCKET;
        }
        else if ( fdcnt == 0 )
        {
            return ERR_TIMEOUT;
        }
    }
    //Set Socket to Blocking again
    if(fcntl(m_Socket,F_SETFL,opts_blocking)<0)
    {
        return ERR_NET_SOCKET;
    }

    m_connectionStatus = STATUS_OPEN;
    return x2e::OK;

如果我用这个功能,我仍然可以连接实际控制并与之通信。但是,如果我用我的TESTSERVER我只是无法连接,选择刚才叶的返回值为0。
所以现在有人会说,我的TESTSERVER是行不通的....但如果​​我使用阻塞connect()调用,我可以发到我TESTSERVER没有任何问题......
也许有人有一个想法,我可以做什么...?

If I use this function I can still connect on the real controller and communicate with it. But if I use my testserver I just can't connect, select just leaves with a return value of 0. So now someone may say that my testserver just doesn't work....but If I use a blocking connect() call I can send to my testserver without any problems... Maybe someone has an idea what I could do...?

推荐答案

与非阻塞套接字connect()的调用可能与连接返回0,仍然没有准备好
在connect()code部分,可以写成这样(我的连接wraper code段从Python实现教训):

with nonblocking socket connect() call may return 0 with the connection is still not ready the connect() code section, may be written like this(my connect wraper code segment learnt from the python implementation):

    if (FAIL_CHECK(connect(sock, (struct sockaddr *) &channel, sizeof(channel)) &&
            errno != EINPROGRESS))
    {
        gko_log(WARNING, "connect error");
        ret = HOST_DOWN_FAIL;
        goto CONNECT_END;
    }

    /** Wait for write bit to be set **/
#if HAVE_POLL
    {
        struct pollfd pollfd;

        pollfd.fd = sock;
        pollfd.events = POLLOUT;

        /* send_sec is in seconds, timeout in ms */
        select_ret = poll(&pollfd, 1, (int)(send_sec * 1000 + 1));
    }
#else
    {
        FD_ZERO(&wset);
        FD_SET(sock, &wset);
        select_ret = select(sock + 1, 0, &wset, 0, &send_timeout);
    }
#endif /* HAVE_POLL */
    if (select_ret < 0)
    {
        gko_log(FATAL, "select/poll error on connect");
        ret = HOST_DOWN_FAIL;
        goto CONNECT_END;
    }
    if (!select_ret)
    {
        gko_log(FATAL, "connect timeout on connect");
        ret = HOST_DOWN_FAIL;
        goto CONNECT_END;
    }

Python版本code段:

python version code segment:

res = connect(s->sock_fd, addr, addrlen);
if (s->sock_timeout > 0.0) {
    if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {
        timeout = internal_select(s, 1);
        if (timeout == 0) {
            /* Bug #1019808: in case of an EINPROGRESS,
               use getsockopt(SO_ERROR) to get the real
               error. */
            socklen_t res_size = sizeof res;
            (void)getsockopt(s->sock_fd, SOL_SOCKET,
                             SO_ERROR, &res, &res_size);
            if (res == EISCONN)
                res = 0;
            errno = res;
        }
        else if (timeout == -1) {
            res = errno;            /* had error */
        }
        else
            res = EWOULDBLOCK;                      /* timed out */
    }
}

if (res < 0)
    res = errno;

这篇关于Linux的TCP连接与选择()在TE​​STSERVER失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆