首页 文章

如何将TCP套接字更改为非阻塞?

提问于
浏览
29

你如何使套接字无阻塞?

我知道 fcntl() 函数,但我've heard it'并不总是可靠的 .

7 回答

  • 0

    我知道这是一个古老的问题,但对于google上的所有人来说,这里寻找有关如何处理阻塞和非阻塞套接字的信息,这是对如何处理套接字的I / O模式的不同方法的深入解释 - http://dwise1.net/pgm/sockets/blocking.html

    快速摘要:

    • So Why do Sockets Block?

    • What are the Basic Programming Techniques for Dealing with Blocking Sockets?

    • Have a design that doesn't care about blocking

    • Using select

    • Using non-blocking sockets.

    • Using multithreading or multitasking

  • 1

    在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");
    }
    
  • 70

    "not always reliable"是什么意思?如果系统成功设置套接字非阻塞,则它将是非阻塞的 . 如果阻塞需要阻塞(例如,如果输出缓冲区已满并且您经常调用发送/写入),则套接字操作将返回 EWOULDBLOCK .

    使用非阻塞调用时,This forum thread有一些好处 .

  • 38

    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
    }
    
  • 1

    你被误导了 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() 设置它 .

  • 14

    fcntl()ioctl() 用于设置文件流的属性 . 当您使用此函数使套接字无阻塞时,像 accept()recv() 等函数本质上是阻塞的,将返回错误, errno 将设置为 EWOULDBLOCK . 您可以轮询文件描述符集以在套接字上轮询 .

  • 19

    通常,使用 select(2)poll(2) 或系统上可用的某些其他系统调用,使用普通的 blocking IOmultiplexing 几个IO操作可以达到相同的效果 .

    有关可扩展IO多路复用方法的比较,请参见The C10K problem .

相关问题