2016-03-27 6 views
0

この質問が以前に聞かれた場合はお詫び申し上げます。私は選択多重化を使用して非ブロッキングソケットクライアントを作成しています。私を混乱させることの1つは、オンラインまたはオフラインになっているサーバーに関係なく、非ブロッキング接続が常に成功することです。私は多くの記事を検索し、彼らのソリューションに従ったが、それらのどれも私のLinuxのubuntuマシンでは動作しません。ノンブロッキングソケット接続は常に成功しますか?

毎回
static void callback_on_select_write(int connect_fd) { 

    // Client write event arrived; 

    int error = -1; 
    socklen_t len = sizeof(error); 

    if(getsockopt(connect_fd, SOL_SOCKET, SO_ERROR, &error, &len) == -1) { 
    return; 
    } 

    // getsockopt puts the errno value for connect into erro so 0 means no-error. 
    if(error == 0) { 
     // Connection ok. 
    } 
    else { 
    cerr << "Failed to connect\n"; 
    return; 
    } 

    // Ready to write/read 

} 

選択戻り、代わりに常に失敗をcerringの、ブロックを「読み/書きする準備ができました」に行く、すなわちを成功このコールバックを呼び出します。なぜこれが起こるのですか?接続が本当に成功したかどうかを検出するポータブルメカニズムを設計するにはどうすればよいですか?以下は、私がコネクタを作成する方法です。毎回

int make_socket_client(const ::std::string& hostname, const ::std::string& port) { 

    struct addrinfo hints; 
    struct addrinfo* res {nullptr}; 
    struct addrinfo* ptr {nullptr}; 

    memset(&hints, 0, sizeof(struct addrinfo)); 
    hints.ai_family = AF_UNSPEC; 
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_protocol = IPPROTO_TCP; 

    int rv; 
    int connector; 

    if((rv = getaddrinfo(hostname.c_str(), port.c_str(), &hints, &res)) != 0) { 
    return -1; 
    } 

    // Try to get the first available client connection. 
    for(ptr = res; ptr != nullptr; ptr = ptr->ai_next) { 

    // Ignore undefined ip type. 
    if(ptr->ai_family != AF_INET && ptr->ai_family != AF_INET6) { 
     continue; 
    } 

    // Create a listener socket and bind it to the localhost as the server. 
    if((connector = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) == -1){ 
     continue; 
    } 

    make_fd_nonblocking(connector); 

    if(connect(connector, (struct sockaddr*)ptr->ai_addr, ptr->ai_addrlen) < 0) { 
     // This is what we expect. 
     if(errno == EINPROGRESS) { 
     break; 
     } 
     else { 
     close(connector); 
     continue; 
     } 
    } 
    else { 
     break; 
    } 
    } 

    freeaddrinfo(res); 

    if(ptr == nullptr) { 
    return -1; 
    } 

    return connector; 
} 
+0

確かにあなたは 'connect_fd'のSO_ERRORを見ているべきですか? 「イベント」とは何ですか?このコードは、質問に答えるのに十分ではありません。 – EJP

+0

申し訳ありません。それはconnect_fdのみでなければなりません。 – Jes

+0

元の 'connect()'はゼロを返しましたか? – EJP

答えて

0

選択戻り、常に はなく cerring障害の、ブロックを「読み/書きする準備ができました」に行く、すなわちを成功このコールバックを呼び出します。なぜこれが起こるのですか?

非同期TCP接続が進行中(connect()呼び出しで-1/EINPROGRESSと表示されている)の間、select()のソケットをwrite-readyソケットセットの一部として渡す必要がありますソケットが書き込み準備ができていることを示すときにselect()が戻るようにします。

TCP接続が成功または失敗すると、select()はソケットが書き込み可能(*)であることを返します。それが起こると、2つの可能な結果(成功または失敗)のどちらが発生したかを把握する必要があります。

以下は、非同期的に接続するソケットselect()が書き込み可能状態のときに呼び出す関数です。

// call this select() has indicated that (fd) is ready-for-write because 
// (fd)'s asynchronous-TCP connection has either succeeded or failed. 
// Returns true if the connection succeeded, false if the connection failed. 
// If this returns true, you can then continue using (fd) as a normal 
// connected/non-blocking TCP socket. If this returns false, you should 
// close(fd) because the connection failed. 
bool FinalizeAsyncConnect(int fd) 
{ 
#if defined(__FreeBSD__) || defined(BSD) 
    // Special case for FreeBSD7, for which send() doesn't do the trick 
    struct sockaddr_in junk; 
    socklen_t length = sizeof(junk); 
    memset(&junk, 0, sizeof(junk)); 
    return (getpeername(fd, (struct sockaddr *)&junk, &length) == 0); 
#else 
    // For most platforms, the code below is all we need 
    char junk; 
    return (send(fd, &junk, 0, 0L) == 0); 
#endif 
} 

(*)サイドノート:物事はWindowsは、物事に独自の方法を行うのが好きので、Windows環境下でわずかに異なります:Windowsでは、成功した非同期(接続)上記のように示されているが、あなたがしたい場合はWindows上で失敗した非同期connect()の試行について通知される場合は、Windowsが失敗した非同期connect()を通信するために使用する "except" fd_setであるため、 "except" fd_setの下にソケットを登録する必要があります。

+0

ありがとう、ジェレミー。しかし、私のOSXシステムでは、ピアをオフラインにしてsendを呼び出すと、 'SIGPIPE'エラーが出てプログラムが終了し、' FinalizeAsyncConnect'関数は返されません。どうすれば解決できますか? – Jes

+1

main()の先頭にあるシグナル(SIGPIPE、SIG_IGN)を呼び出すことでSIGPIPEを無効にします。http://stackoverflow.com/questions/108183/how-to-prevent-sigpipes-or-handle-them-properly/108192#108192 –

関連する問題