2011-08-17 94 views
1

我的问题是以下内容: 我正在编程接口在Linux中通过以太网控制GPIB控制器。为此,我打开一个TCP套接字并将这些命令发送给Controller。到目前为止,这工作得很好。我在为我的接口编写某种单元测试时发生了这个问题: 要检查我是否在单独的线程中使用来自boost lib的tcp接受器,并且只是连接到它而不是实际的控制器。这也起作用,但只要来自接口的connect()调用被阻塞即可。然而,因为我需要为连接指定的超时()调用我不得不用select()函数连接:Linux的TCP连接与选择()失败在测试服务器

// 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; 

如果我用这个功能,我仍然可以连接真实控制器上,并与它进行通信。但是,如果我使用我的测试服务器,我只是无法连接,只选择返回值为0的叶子。 因此,现在有人可能会说我的测试服务器不工作....但如果我使用阻塞连接()打电话我可以发送到我的测试服务器没有任何问题... 也许有人有一个想法我可以做什么......?

+0

的零的返回值表示超时。这可能会也可能不是问题,但您似乎并未在发布的摘录中设置超时结构。引用手册页“在Linux上,select()修改超时以反映未睡眠的时间量......考虑超时在select()返回后未定义。”如果您在不重置值的情况下再次调用它,会导致问题。 –

+0

对不起我的错,我忘了将timeouts结构的定义添加到我的代码中!要解决这个问题......但这也意味着这不是问题:/ /所以现在的代码包含处理连接的整个功能 – Toby

+0

你是否知道你没有关闭任何地方的插座?你没有重复使用它,使用相同的套接字多次连接,你呢? – rodrigo

回答

2

与非阻塞套接字connect()调用可以与连接返回0,是还没有准备好 的connect()代码段,可以这样写(我的连接wraper代码段从Python实现学):

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; 
    } 

蟒版本代码段:

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;