public class ServerThread implements Runnable
{
private static final int port = 10000;
@Override
public void run() {
ServerSocket serverSocket = new ServerSocket(port);
while (true) {
Socket clientSocket = serverSocket.accept();
ClientThread clientThread = new ClientThread(clientSocket);
// handle the client request in a separate thread
}
}
}
如果我有 10 个不同的线程运行 ServerThread.run(),这会起作用吗?或者我应该为所有线程使用相同的 ServerSocket 对象吗?
文档说:
ServerSocket 的构造函数在无法监听指定端口时抛出异常(例如,该端口已被使用)
您可能想知道为什么我首先要这样做,而不是简单地让一个线程运行 ServerSocket.accept()。好吧,我的假设是(如果我错了请纠正我)accept() 方法可能需要一些时间才能完成建立连接,特别是如果 ServerSocket 是 SSL(因为握手)。所以如果两个客户端同时想要连接,一个必须等待另一个。这对于高流量服务器来说是非常糟糕的。
更新:似乎 accept() 方法将在属于队列的连接建立后立即返回。这意味着如果有一排客户端等待连接,服务器线程可以以最快的方式处理请求并且只需要一个线程。(除了为每个请求创建一个新线程并启动线程所花费的时间,但使用线程池时该时间可以忽略不计)
ServerSocket 还有一个名为“backlog”的参数,您可以在其中设置队列中的最大连接数。根据《Java 基础网络》一书 3.3.3
TCP 本身可以在接受连接方面领先于 TCP 服务器应用程序。它维护一个连接到侦听套接字的“积压队列”,TCP 本身已完成但尚未被应用程序接受。这个队列存在于底层 TCP 实现和创建监听套接字的服务器进程之间。预完成连接的目的是加快连接阶段,但队列的长度是有限的,以免预先形成太多与服务器的连接,这些服务器由于任何原因不以相同的速率接受它们。当接收到传入连接请求且积压队列未满时,TCP 完成连接协议并将连接添加到积压队列。此时,客户端应用程序已完全连接,但服务器应用程序尚未收到连接作为 ServerSocket.accept 的结果值。当它这样做时,该条目将从队列中删除。
我仍然不确定在 SSL 的情况下,握手是否也由 ServerSocket.accept() 并行完成以进行同时连接。
更新 2 ServerSocket.accept() 方法本身根本不做任何真正的网络。一旦操作系统建立了新的 TCP 连接,它就会返回。操作系统本身持有一个等待 TCP 连接的队列,可以通过 ServerSocket 构造函数中的“backlog”参数来控制:
ServerSocket serverSocket = new ServerSocket(port, 50); //this will create a server socket with a maximum of 50 connections in the queue
SSL 握手在客户端调用 Socket.connect()之后完成。因此,一个 ServerSocket.accept() 线程就足够了。
慕标5832272
相关分类