【问题标题】:Winsock send() blocks server?Winsock send() 阻塞服务器?
【发布时间】:2012-10-17 20:55:59
【问题描述】:

我读到 Winsock 上的 send() 函数会阻塞,直到收到最后一个数据包的 ACK。现在我正在使用服务器进行回合制角色扮演游戏。一切都由一个线程处理(对于 64 个套接字)。接收、处理请求并将响应写入套接字。此过程不能中断。

是否可以使用这种方法处理 1000 个客户端(每 64 个套接字一个线程)?

如果 send() 完成时间过长或客户端恶意不发送 ACK 或连接中断,它不会阻塞整个服务器吗?

我应该将网络和请求处理的逻辑分成 2 个线程吗?如果是这样,处理网络传输的线程仍然可能被 send() 或 recv() 阻塞。

或者最好使用重叠 I/O?

【问题讨论】:

    标签: multithreading block winsock send blocking


    【解决方案1】:

    send() 仅在套接字以阻塞模式运行并且套接字的出站缓冲区填满排队数据时才会阻塞。如果您在同一个线程中管理多个套接字,请不要使用阻塞模式。如果一个接收器没有及时读取数据,可能会导致该线程上的所有连接都受到影响。改用非阻塞模式,然后send()会在socket进入阻塞状态时报告,然后你可以使用select()来检测socket何时可以再次接受新数据。更好的选择是改用重叠 I/O 或 I/O 完成端口。向操作系统提交出站数据,让操作系统处理所有等待您的事情,并在数据最终被接受/发送时通知您。在收到通知之前,不要为给定的套接字提交新数据。对于大量连接的可扩展性,I/O 完成端口通常是更好的选择。

    【讨论】:

    • 你能解释一下为什么如果使用多个线程会有所不同吗?套接字是通过线程共享的吧?
    【解决方案2】:

    不,它不是那样工作的。来自send 上的 MSDN 文档:

    发送功能的成功完成并不表示数据已成功交付和接收到接收者。该函数仅表示数据发送成功。

    【讨论】:

    • 不仅如此,它实际上并不表示数据成功发送到接收方,而是成功在socket的队列中排队出站缓冲区,用于稍后传输到接收器。如果send() 阻塞,则表示套接字正在以阻塞模式运行并且队列已满,等待接收方读取并确认一些数据,以便在队列中打开空闲空间。