web-dev-qa-db-ja.com

Linux、ソケット、ノンブロッキング接続

ノンブロッキング接続を作成したい。このような:

socket.connect(); // returns immediately

これには、別のスレッド、無限ループとLinux epollを使用します。このように(擬似コード):

// in another thread
{
  create_non_block_socket();
  connect();

  epoll_create();
  epoll_ctl(); // subscribe socket to all events
  while (true)
  {
    epoll_wait(); // wait a small time(~100 ms)
    check_socket(); // check on EPOLLOUT event
  }
}

サーバーを実行してからクライアントを実行すると、すべて機能します。最初にクライアントを実行した場合、少し待ってからサーバーを実行すると、クライアントが接続しません。

何が悪いのですか?多分それは別の方法で行うことができますか?

14
herolover

非同期接続には次の手順を使用する必要があります。

  • socket(..., SOCK_NONBLOCK, ...)でソケットを作成する
  • connect(fd, ...)で接続を開始します
  • 戻り値が_0_でもEINPROGRESSでもない場合、エラーで中止します
  • fdが出力可能として通知されるまで待機します
  • getsockopt(fd, SOL_SOCKET, SO_ERROR, ...)でソケットのステータスをチェックします
  • できた

ループなし-EINTRを処理する場合を除きます。

クライアントが最初に起動された場合、最後のステップでエラーECONNREFUSEDが表示されます。この場合は、ソケットを閉じて、最初からやり直してください。

詳細を確認しないと、コードのどこに問題があるのか​​を知ることは困難です。 _check_socket_オペレーションでエラーが発生しても中止しないと思います。

36
nosid

ノンブロッキング接続が成功するかどうかをテストする方法はいくつかあります。

  1. 最初にgetpeername()を呼び出します。エラーENOTCONNで失敗した場合、接続は失敗しました。次に、SO_ERRORを指定してgetsockoptを呼び出し、ソケットで保留中のエラーを取得します
  2. 長さが0のreadを呼び出します。読み取りが失敗した場合、接続は失敗し、読み取りのerrnoは接続が失敗した理由を示します。接続が成功した場合、readは0を返します
  3. もう一度接続を呼び出します。 errnoがEISCONNの場合、接続はすでに接続されており、最初の接続は成功しました。

参照:UNIXネットワークプログラミングV1