如何将TCP套接字更改为非阻塞?
你如何使一个套接字非阻塞?
我知道fcntl()
函数,但我听说它并不总是可靠的。
你是什么意思“不总是可靠的”? 如果系统成功设置你的套接字是非阻塞的,它将是非阻塞的。 如果它们阻塞需要阻塞(例如,如果输出缓冲区已满并且您经常调用发送/写入),套接字操作将返回EWOULDBLOCK
。
使用非阻塞调用时, 这个论坛线程有几个好处。
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 < 0) 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()
从一开始就创build非阻塞的socket()
。
例如
// 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()
用于设置文件stream的属性。 当你使用这个函数来创build一个非阻塞的套接字时, accept()
, recv()
等function将被返回错误, errno
将被设置为EWOULDBLOCK
。 您可以轮询文件描述符集以在套接字上轮询。
一般来说,通过使用普通的阻塞IO并使用select(2)
, poll(2)
或系统上可用的一些其他系统调用复用几个IO操作,可以达到相同的效果。
请参阅C10K问题以比较可伸缩IO多路复用的方法。
在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"); }