2011-08-17 40 views
1

私の問題は次のとおりです。 イーサネット経由でGPIBコントローラを制御するために、Linuxのインターフェイスをプログラミングしています。そうするために、私はTCPソケットを開き、コマンドをコントローラに送るだけです。今のところうまくいきます。 チェックするには、別のスレッドで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; 

:しかし、私は(接続のために指定されたタイムアウトを必要とするので)が、私はselect()関数に接続しなければならなかった呼び出します。しかし、私は私のテストサーバーを使用する場合、私は接続することはできません、戻り値0の葉だけを選択してください。 だから今誰かが私のテストサーバーが動作しないと言うかもしれません....しかし、私はテストサーバーに何の問題もなく送信することができます。 多分誰かが私ができることを考えています...?ノンブロッキングソケット接続()呼び出しは、接続して0を返すことがで

+0

ゼロの戻り値は、タイムアウトを示します。これは問題かもしれませんが、投稿された抜粋内にタイムアウト構造体を設定していないようです。マニュアルページ "Linuxでselect()を実行すると、スリープしていない時間が反映されるようにタイムアウトが変更されます。select()が戻った後にタイムアウトが定義されていないと考えてください。値をリセットせずに再度呼び出すと問題が発生します。 –

+0

申し訳ありませんが私のせいで、タイムアウトの構造体の定義を自分のコードに追加するのを忘れました!!!それを修正するつもりです...しかし、それは問題ではないことを意味します:/ /さて、コードには接続を扱う関数全体が含まれています – Toby

+0

あなたはどこにでもソケットを閉じないのですか?あなたはそれを再使用していない、同じソケットで数回接続するのですか? – rodrigo

答えて

2

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

Pythonバージョンのコードセグメント:

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; 
関連する問題