Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sockets 使用多个套接字,非阻塞还是使用select阻塞更好?_Sockets_Winsock_Blocking_Nonblocking - Fatal编程技术网

Sockets 使用多个套接字,非阻塞还是使用select阻塞更好?

Sockets 使用多个套接字,非阻塞还是使用select阻塞更好?,sockets,winsock,blocking,nonblocking,Sockets,Winsock,Blocking,Nonblocking,假设我有一个服务器程序,可以接受来自10个(或更多)不同客户端的连接。客户端随机发送由服务器接收的数据,但可以肯定的是,每次更新至少会有一个客户端发送数据。服务器无法等待信息到达,因为它还有其他处理要做。除了使用异步套接字之外,我还看到两个选项: 使所有插座无阻塞。在循环中,在每个套接字上调用recv(),如果没有可用的数据,并且如果我碰巧获得了一些数据,则允许它通过WSAEWOULDBLOCK失败,然后保留它 让插座保持阻塞状态。将所有套接字添加到FD\u集合并调用select()。如果返回值

假设我有一个服务器程序,可以接受来自10个(或更多)不同客户端的连接。客户端随机发送由服务器接收的数据,但可以肯定的是,每次更新至少会有一个客户端发送数据。服务器无法等待信息到达,因为它还有其他处理要做。除了使用异步套接字之外,我还看到两个选项:

  • 使所有插座无阻塞。在循环中,在每个套接字上调用
    recv()
    ,如果没有可用的数据,并且如果我碰巧获得了一些数据,则允许它通过
    WSAEWOULDBLOCK
    失败,然后保留它

  • 让插座保持阻塞状态。将所有套接字添加到
    FD\u集合
    并调用
    select()
    。如果返回值为非零(大多数情况下都是非零),则使用
    FD_ISSET()
    遍历所有套接字以找到适当数量的可读套接字,并且只调用可读套接字上的
    recv()

  • 第一个选项将创建更多对
    recv()
    函数的调用。从编程的角度来看,第二种方法是一种更大的痛苦,因为所有的
    FD_集
    FD_集
    循环

    首选哪种方法(或其他方法)?避免让非阻塞套接字上的
    recv()
    失败的开销值得调用
    select()

    我想我对这两种方法都很了解,并且两种方法都试过了,但我不知道哪种方法被认为是更好的还是最佳的。

    我建议改用。然后可以启动,并提供一个回调函数,以便在操作完成时调用。更重要的是,由于它只在程序处于可警报等待状态时才会被调用,因此您不必像在线程应用程序中那样担心锁(假设您在主线程上运行锁)

    但是,请注意,您确实需要经常输入这种可警报的等待状态。如果这是您的UI线程,请确保在消息循环中使用
    MWMO\u ALERTABLE
    标志。这将使您的回调有机会运行。在非UI线程上,定期调用使您进入可警报等待状态的任何线程

    还请注意,模式对话框通常不会进入可警报的等待状态,因为它们有自己的消息循环,该循环不调用
    MsgWaitForMultipleObjectsEx()
    。如果在显示对话框时需要处理网络IO,请在专用线程上执行所有网络IO,该线程会定期进入可警报的等待状态

    无论出于何种原因,如果不能使用重叠IO,则一定要使用阻塞
    select()
    。像在无限循环中那样使用非阻塞
    recv()
    ,是对CPU时间的不可原谅的浪费。但是,一定要将套接字置于非阻塞模式——否则,如果一个字节到达,而您试图读取两个字节,那么您可能会意外地阻塞


    您可能还想考虑使用一个库来抽象细腻的细节。例如,或者。

    IO应该完全阻塞,每个连接一个线程,在这种情况下,事件循环本质上是一个OS调度程序,或者IO应该完全非阻塞,在这种情况下,基于select/waitformultipleobjects的事件循环将在应用程序中

    所有中间变量都不是很容易维护和出错的

    当并发连接数量增加且没有线程上下文切换开销时,完全非阻塞方法的扩展性更好,因此在并发连接数量不固定的情况下,它是首选方法。与完全阻塞方法相比,这种方法具有更高的实现复杂性


    对于完全非阻塞IO,应用程序的核心是基于select/waitformultipleobjects的事件循环,所有套接字都处于非阻塞模式,所有读/写操作通常在事件循环线程内完成(对于最高性能的写操作,可先从请求写操作的线程直接尝试)

    谢谢。对于这个实现,我不想使用重叠IO,但感谢您的建议。我会调查的。我理解您关于使用非阻塞模式并选择()的建议。我的主要问题是,我应该无缘无故地调用recv,还是通过调用select()来实现。谢谢你的回复!更新了一点以使其更清晰-只需循环使用
    recv()
    ,CPU就会达到100%,这绝不是一件好事。