ソケットを非ブロッキングにする方法は?
fcntl()
関数は知っていますが、必ずしも信頼できるとは限りません。
「常に信頼できるとは限らない」とはどういう意味ですか?システムがソケットの非ノンブロッキング設定に成功すると、非ブロッキングになります。ソケット操作は、ブロックする必要がある場合にEWOULDBLOCK
を返します(たとえば、出力バッファーがいっぱいで、send/writeを頻繁に呼び出している場合)。
このフォーラムスレッド ノンブロッキングコールで作業する場合、いくつかの良い点があります。
fcntl()
は私にとって常に確実に機能しました。いずれにせよ、ソケットのブロックを有効/無効にするために使用する関数は次のとおりです。
#include <fcntl.h>
/** Returns true on success, or false if there was an error */
bool SetSocketBlockingEnabled(int fd, bool blocking)
{
if (fd < 0) return false;
#ifdef _WIN32
unsigned long mode = blocking ? 0 : 1;
return (ioctlsocket(fd, FIONBIO, &mode) == 0) ? true : false;
#else
int flags = fcntl(fd, F_GETFL, 0);
if (flags == -1) return false;
flags = blocking ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
return (fcntl(fd, F_SETFL, flags) == 0) ? true : false;
#endif
}
fcntl()
が常に信頼できるとは限らないという誤った情報があります。それは真実ではありません。
ソケットを非ブロックとしてマークするには、コードは次のように簡単です。
_// where socketfd is the socket you want to make non-blocking
int status = fcntl(socketfd, F_SETFL, fcntl(socketfd, F_GETFL, 0) | O_NONBLOCK);
if (status == -1){
perror("calling fcntl");
// handle the error. By the way, I've never seen fcntl fail in this way
}
_
Linuxでは、2.6.27を超えるカーネルでは、 socket()
および accept4()
を使用して、最初からノンブロッキングのソケットを作成することもできます。 。
例えば.
_ // client side
int socketfd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0);
// server side - see man page for accept4 under linux
int socketfd = accept4( ... , SOCK_NONBLOCK);
_
少しの作業は節約できますが、移植性が低いため、fcntl()
で設定する傾向があります。
fcntl()
またはioctl()
は、ファイルストリームのプロパティを設定するために使用されます。この関数を使用してソケットを非ブロッキングにすると、accept()
、recv()
などのような、本来ブロッキングしている関数はエラーを返し、errno
はEWOULDBLOCK
に設定します。ファイル記述子セットをポーリングして、ソケットでポーリングできます。
通常、通常のブロッキングIOとmultiplexingを使用して同じ効果を達成できます。いくつかのIO select(2)
、poll(2)
、またはシステムで使用可能な他のシステムコールを使用した操作。
スケーラブルIO多重化へのアプローチの比較については C10K問題 を参照してください。
私はそれが古い質問であることを知っていますが、ここでブロックおよび非ブロッキングソケットを処理する方法に関する情報を探しているGoogleのすべての人にとって、ソケットのI/Oモードを処理するさまざまな方法の詳細な説明です- http://dwise1.net/pgm/sockets/blocking.html 。
簡単な要約:
では、なぜソケットがブロックするのですか?
ブロッキングソケットを処理するための基本的なプログラミング手法は何ですか?
Cでソケットを非ブロッキングとして設定する最良の方法は、ioctlを使用することです。受け入れられたソケットが非ブロックに設定されている例は次のとおりです。
long on = 1L;
unsigned int len;
struct sockaddr_storage remoteAddress;
len = sizeof(remoteAddress);
int socket = accept(listenSocket, (struct sockaddr *)&remoteAddress, &len)
if (ioctl(socket, (int)FIONBIO, (char *)&on))
{
printf("ioctl FIONBIO call failed\n");
}