1 回答
TA贡献1966条经验 获得超4个赞
以下是关于您的问题的一些想法:
您不能listen()
在同一个 IP+端口上使用多个ServerSocket
. 如果可以,操作系统会将 SYN 数据包传输到哪个套接字?*
TCP 确实维护了预先接受的连接的积压,因此调用将accept()
(几乎)立即返回积压队列中的第一个(最旧的)套接字。它通过自动发送 SYN-ACK 数据包来回复客户端发送的 SYN,并等待回复 ACK(3 次握手)来实现。但是,正如@zero298 所建议的那样,尽可能快地接受连接通常不是问题。问题将是处理与您将接受的所有套接字的通信所产生的负载,这很可能会使您的服务器崩溃(这实际上是一次 DoS 攻击)。实际上这个参数通常在这里 太多并发连接在积压队列中等待太久backlog
accept()
在到达您的应用程序之前,ed 将被 TCP 丢弃。
我建议您使用ExecutorService
线程池来运行某个最大数量的线程,而不是为每个客户端套接字创建一个线程,每个线程处理与一个客户端的通信。这允许系统资源的优雅降级,而不是创建数百万个线程,这反过来会导致线程饥饿、内存问题、文件描述符限制……再加上精心选择的积压值,您将能够获得您的服务器在不崩溃的情况下可以提供的最大吞吐量。run()
如果您担心 SSL 上的 DoS,您的客户端线程方法应该做的第一件事就是调用startHandshake()
新连接的套接字。
关于 SSL 部分,TCP 本身不能做任何 SSL 预接受,因为它需要执行加密/解码、与密钥库对话等,这远远超出了它的规范。请注意,在这种情况下您还应该使用SSLServerSocket
。
积压队列用于 TCP 堆栈已完成但尚未被应用程序接受的连接。与 SSL 无关。JSSE 不会进行任何协商,直到您在已接受的套接字上执行一些 I/O,或在其上调用 startHandshake(),这两者都将在处理连接的线程中执行。我看不出如何利用它制造 DOS 漏洞,至少不是特定于 SSL 的漏洞。如果您遇到 DOS 情况,很可能您正在 accept() 线程中执行本应在连接处理线程中完成的 I/O。
*:虽然Linux >=3.9 做了某种负载平衡,但仅适用于 UDP(所以不是 SSLServerSocket
)并且有选项SO_REUSEPORT
,这并不是在所有平台上都可用。
添加回答
举报