この機能を提供するいくつかの容易に利用可能なソフトウェアライブラリがあります。私が考えることができる主なものはカールです。 カールマルチライブラリhereへの簡単な紹介を見つけることができます。
非常に良い理由(技術の向上や学術研究の改善など)がない限り、ホイールの再発明は避けるのが最善です。
学術研究のため、また「リンク専用」の回答で十分ではないので、私はマルチプレクサソケットに関する多くの可能な方法の1つについて詳しく説明します。
ノンブロッキングソケット
まず、現在はほとんどのポータブル方法は、非ブロッキングソケットおよび/または非ブロックソケット呼び出しを使用することで、しかし、使用して(場合は特に認識することが重要ですノンブロッキングソケットは、O_NONBLOCK
をファイル記述子に設定するのではなく、を呼び出します。一部のものはまだブロックされます。たとえば、ファイル記述子を非ブロックモードに設定し、もちろんgetaddrinfo
(同様の標準的な名前解決関数)もブロックしない限り、connect
をすぐに返すことはできません。
非ブロッキングファイルや関数呼び出しを使用すると、関数はすぐに戻ります。データが準備されていない場合、戻り値によってこれが示されます。処理できるデータがある場合は、再び戻り値が表示されます。
ノンブロッキングソケットコール(connect
を含む)を確実にする方法は2つあります。
- UNIXシステムの場合は、
fcntl(socket_fd, fcntl(socket_fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK)
を呼び出します。その後、read
、write
、accept
、connect
へのすべてのコールは、すぐに返されます。には、EALREADY
,EINPROGRESS
、EISCONN
、EWOULDBLOCK
のようないくつかのエラーコードがあります(ノンブロッキングを有効にすると、は実際には成功戻り値です)。変装で; errno
をチェックする必要があります。
Windowsシステムの場合は、ioctlsocket(socket_fd, FIONBIO, (u_long[]){1})
を呼び出します。 errno
コードがerrno
コード(代わりにGetLastError()
コードになる)を除いて、同じセマンティクスが上記のように発生します...おそらく異なる値ですが、わかりません。私は、
#ifdef _WIN32
#define set_nonblock(fd) (ioctlsocket(fd, FIONBIO, (u_long[]){1}) == 0)
#define EAGAIN WSAEWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EISCONN WSAEISCONN
#define EINPROGRESS WSAEINPROGRESS
#define EINVAL WSAEINVAL
#define EALREADY WSAEALREADY
#else
#define set_nonblock(fd) (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) != -1)
#endif
だけではない、非ブロッキングソケットを使用して
言及に値する:私のプロジェクトで、私は通常のようなものを使用して、しかし、似た名前を持つ彼らの多くわずかな調整だけで、さまざまなシステム上で、1つのスレッドで数千の接続を維持することができれば、全く驚くことはありません。しかし、各ソケットを循環するためにビジーループが必要なので、このモデルは理想的ではありません。ループごとにイベントを瞬時にテストします。たとえば、イベントが到着したときにOSによって起動するようにコードがトリガされるのではなく、
イベントをアプリケーションに送信するには、カーネルがイベントを処理する必要があるので、たとえばsleep(0);
をクイックフィックスとして使用してください。これにより、CPU使用率が100%近くから10%に低下することが確認されます。しかしながら、機能がとなるように、ブロックされていない(またはタイムアウト中断された)機能を持つ多数の(ブロッキングまたは非ブロッキング)ソケットを多重化する別の方法があります。は、データを受信する。
select
が明らかに強力な利点を有するが、欠点もある。つまり、セットは通常、ソケットの数が少ないことに制限されています。多数のソケットをサポートするには、64ソケット制限(またはそれが何であれ)がすぐに使い果たされるので、ループ内にループが必要です。さらに、は、connect
ブロック問題を解決しません(ここでは、O_NONBLOCK
と〜FIONBIOメソッドがします)。
このように、私はselect
についてこれ以上話しません。 他のオプションについてご説明します。同様の制限を伴う別の例は、poll
です。私はそれについても話しません。あなたはそれについて知りたい場合は、それについては、インターネット上でたくさん...あなたが共通にそれらのすべてをラップする方法を見つけるかもしれませんがこの時点からすべてが(かなり非ポータブルであること
注意がありますインターフェイス、カールマルチのように)。
非同期ソケットは、接続を開始し、彼らはまた、信号を上げたり、接続が完了したときに指定した関数を呼び出しますを除いて、その後、非ブロックソケット呼び出しのようにすぐに戻りますを呼び出します。これは、OSがあなたを待っているのではなく、イベントが到着したときにあなたのコードに通知するようにOSを制御しています。最適化が進む限り、非同期ソケットは理想的ですが、は移植性がありません。 OSごとにさまざまなオプションがあります:FreeBSD用のLinux
kqueue
ため
これらのすべてに共通点があります。これは、成功または失敗時に関数を呼び出す(または関数の呼び出しに変換できるシグナルを発生させる)ことです。しかし、そのインタフェースはあまりよく知られているものではありません。
通常、私はこの回答の冒頭で述べたノンブロッキングソケットが今日よりはるかに適切であることを知っているので、それらのラッパーを作成するのは面倒ではありません。重要なのは、私はそれをすべてのシステムに移植する必要はないということです。なぜなら、私はあまりにも怠け者だからです!誰かがそのシステムで遅いことを私に示すとき、私はシステムに対してのみ最適化します。さもなければ、私たちは、人々が私たちのソフトウェアを使用していないかもしれないシステムの急流に自分自身を掘り下げてしまう...
代わりにスレッド上でチュートリアルを探し始めることをお勧めします。ダウンロードが1つのプロセスですべて完了した場合、ダウンロードを同期する方が簡単かもしれません。それ以外の場合は、共有メモリや共有ファイル、ファイルロックに関するチュートリアルを参照してください。 –
子供にスレッドを使用することは可能ですか? – rschirin
一般に、子プロセスとスレッドは混在させずに、どちらか一方を使用します。複数のスレッドはすべて、それらを作成したプロセスのリソースを共有しますが、別のプロセスは何も共有しません。 –