1.创建带连接池的多线程文件传输服务器和客户端
我们现在已经拥有的 MultithreadedServer
每当有客户机申请一个连接时都在一个新 Thread
中创建一个新 ConnectionHandler
。这意味着可能有一捆 Thread
“躺”在我们周围。而且创建 Thread
的系统开销并不是微不足道的。如果性能成为了问题(也请不要事到临头才意识到它),更高效地处理我们的服务器是件好事。那么,我们如何更高效地管理服务器端呢?我们可以维护一个进入的连接池,一定数量的ConnectionHandler
将为它提供服务。这种设计能带来以下好处:
- 它限定了允许同时连接的数目。
- 我们只需启动
ConnectionHandler
Thread
一次。
幸运的是,跟在我们的多线程示例中一样,往代码中添加“池”不需要来一个大改动。事实上,应用程序的客户机端根本就不受影响。在服务器端,我们在服务器启动时创建一定数量的 ConnectionHandler
,我们把进入的连接放入“池”中并让 ConnectionHandler
打理剩下的事情。这种设计中有很多我们不打算讨论的可能存在的技巧。例如,我们可以通过限定允许在“池”中建立的连接的数目来拒绝客户机。
请注意:我们将不会再次讨论 acceptConnections()
。这个方法跟前面示例中的完全一样。它无限循环地调用 ServerSocket
上的 accept()
并把连接传递到 handleConnection()
。
2. 创建 PooledRemoteFileServer 类
这里是 PooledRemoteFileServer
类的结构:
请注意一下您现在应该熟悉了的 import
语句。我们给类以下实例变量以保存:
- 我们的服务器能同时处理的活动客户机连接的最大数目
- 进入的连接的侦听端口(我们没有指定缺省值,但如果您想这样做,并不会受到限制)
- 将接受客户机连接请求的
ServerSocket
类的构造器用的参数是侦听端口和连接的最大数目
我们的类有一个 main()
方法和三个其它方法。稍后我们将探究这些方法的细节。现在只须知道 setUpHandlers()
创建数目为 maxConnections
的大量 PooledConnectionHandler
,而其它两个方法则与我们前面已经看到的相似:acceptConnections()
在 ServerSocket
上侦听传入的客户机连接,而 handleConnection
则在客户机连接一旦被建立后就实际处理它。
3. 实现 main()
这里我们实现需作改动的 main()
方法,该方法将创建能够处理给定数目的客户机连接的 PooledRemoteFileServer
,并告诉它接受连接:
我们的 main()
方法很简单。我们实例化一个新的 PooledRemoteFileServer
,它将通过调用 setUpHandlers()
来建立三个PooledConnectionHandler
。一旦服务器就绪,我们就告诉它 acceptConnections()
。
4. 建立连接处理程序