[英]How do I change a TCP socket to be non-blocking?
How do you make a socket non-blocking?你如何使套接字非阻塞?
I am aware of the fcntl()
function, but I've heard it's not always reliable.我知道
fcntl()
函数,但我听说它并不总是可靠的。
fcntl()
has always worked reliably for me. fcntl()
对我来说一直很可靠。 In any case, here is the function I use to enable/disable blocking on a socket:无论如何,这是我用来启用/禁用套接字阻塞的函数:
#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
}
You're misinformed about fcntl()
not always being reliable.你被误导了
fcntl()
并不总是可靠的。 It's untrue.这是不真实的。
To mark a socket as non-blocking the code is as simple as:要将套接字标记为非阻塞,代码非常简单:
// 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
}
Under Linux, on kernels > 2.6.27 you can also create sockets non-blocking from the outset using socket()
and accept4()
.在 Linux 下,在内核 > 2.6.27 上,您还可以使用
socket()
和accept4()
从一开始就创建非阻塞socket()
。
eg例如
// 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);
It saves a little bit of work, but is less portable so I tend to set it with fcntl()
.它节省了一点工作,但便携性较差,因此我倾向于使用
fcntl()
进行设置。
What do you mean by "not always reliable"? “并不总是可靠的”是什么意思? If the system succeeds in setting your socket non non-blocking, it will be non-blocking.
如果系统成功地将您的套接字设置为非阻塞,它将是非阻塞的。 Socket operations will return
EWOULDBLOCK
if they would block need to block (eg if the output buffer is full and you're calling send/write too often).如果套接字操作需要阻塞(例如,如果输出缓冲区已满并且您过于频繁地调用发送/写入),则套接字操作将返回
EWOULDBLOCK
。
This forum thread has a few good points when working with non-blocking calls.在处理非阻塞调用时,这个论坛线程有几个优点。
fcntl()
or ioctl()
are used to set the properties for file streams. fcntl()
或ioctl()
用于设置文件流的属性。 When you use this function to make a socket non-blocking, function like accept()
, recv()
and etc, which are blocking in nature will return error and errno
would be set to EWOULDBLOCK
.当您使用此函数使套接字非阻塞时,像
accept()
、 recv()
等本质上阻塞的函数将返回错误并且errno
将设置为EWOULDBLOCK
。 You can poll file descriptor sets to poll on sockets.您可以轮询文件描述符集以轮询套接字。
I know it's an old question, but for everyone on google ending up here looking for information on how to deal with blocking and non-blocking sockets here is an in depth explanation of the different ways how to deal with the I/O modes of sockets - http://dwise1.net/pgm/sockets/blocking.html .我知道这是一个老问题,但对于谷歌上的每个人来说,最终在这里寻找有关如何处理阻塞和非阻塞套接字的信息,这是对如何处理套接字 I/O 模式的不同方法的深入解释- http://dwise1.net/pgm/sockets/blocking.html 。
Quick summary:快速总结:
So Why do Sockets Block?那么为什么套接字会阻塞呢?
What are the Basic Programming Techniques for Dealing with Blocking Sockets?处理阻塞套接字的基本编程技术有哪些?
If you want to change socket to non blocking , precisely accept() to NON-Blocking state then如果你想改变插座非阻塞,正是接受()非阻塞状态,则
int flags=fcntl(master_socket, F_GETFL);
fcntl(master_socket, F_SETFL,flags| O_NONBLOCK); /* Change the socket into non-blocking state F_SETFL is a command saying set flag and flag is 0_NONBLOCK */
while(1){
if((newSocket = accept(master_socket, (struct sockaddr *) &address, &addr_size))<0){
if(errno==EWOULDBLOCK){
puts("\n No clients currently available............ \n");
continue;
}
}else{
puts("\nClient approched............ \n");
}
}
On Linux and BSD you can directly create the socket in non-blocking mode ( https://www.man7.org/linux/man-pages/man7/socket.7.html ):在 Linux 和 BSD 上,您可以直接以非阻塞模式创建套接字 ( https://www.man7.org/linux/man-pages/man7/socket.7.html ):
int fd = socket(res->ai_family, res->ai_socktype | SOCK_NONBLOCK | SOCK_CLOEXEC, res->ai_protocol);
if (fd == -1) {
perror("socket");
return -1;
}
When accepting connections you can use the accept4
function to directly accept new connections in non-blocking mode ( https://man7.org/linux/man-pages/man2/accept.2.html ):接受连接时,您可以使用
accept4
函数以非阻塞模式直接接受新连接( https://man7.org/linux/man-pages/man2/accept.2.html ):
int fd = accept4(lfd, NULL, 0, SOCK_NONBLOCK | SOCK_CLOEXEC);
if (fd == -1) {
perror("accept4");
return -1;
}
I don't know why the accepted answer doesn't mention this.我不知道为什么接受的答案没有提到这一点。
Generally you can achieve the same effect by using normal blocking IO and multiplexing several IO operations using select(2)
, poll(2)
or some other system calls available on your system.通常,您可以通过使用普通阻塞 IO并使用
select(2)
、 poll(2)
或系统上可用的其他一些系统调用来复用多个 IO 操作来实现相同的效果。
See The C10K problem for the comparison of approaches to scalable IO multiplexing.有关可扩展 IO 多路复用方法的比较,请参阅C10K 问题。
The best method for setting a socket as non-blocking in C is to use ioctl.在 C 中将套接字设置为非阻塞的最佳方法是使用 ioctl。 An example where an accepted socket is set to non-blocking is following:
接受的套接字设置为非阻塞的示例如下:
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");
}
It is sometimes convenient to employ the "send/recv" family of system calls.有时使用“send/recv”系列系统调用会很方便。 If the
flags
parameter contains the MSG_DONTWAIT
flag, each call will behave similar to a socket having the O_NONBLOCK
flag set.如果
flags
参数包含MSG_DONTWAIT
标志,则每次调用的行为都类似于设置了O_NONBLOCK
标志的套接字。
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.