多线程的TCP网络程序
在上一小节的两个案例中,分别实现了服务器端程序和客户端程序,当一个客户端程序请求服务器端时,服务器端就会结束阻塞状态,完成程序的运行。实际上,很多服务器端程序都是允许被多个应用程序访问的,例如门户网站可以被多个用户同时访问,因此服务器端都是多线程的。下面就通过一个图例来表示多个用户访问同一个服务器,如图1所示。
图1 多个客户端访问服务器端
在图1中,服务器端为每个客户端创建一个对应的Socket对象,并且开启一个新的线程使两个Socket建立专线进行通信。
接下来根据图19所示的多线程通信方式对服务端程序进行改进,如文件1所示。
文件1 ThreadTCPServer.java
1 import java.io.*;
2 import java.net.*;
3 // TCP服务端
4 public class ThreadTCPServer {
5 public static void main(String[] args) throws Exception {
6 // 创建一个指定端口号为7788的服务器端ServerSocket对象
7 ServerSocket serverSocket = new ServerSocket(7788);
8 // 使用while循环不停的接收客户端发送的请求
9 while (true) {
10 // 调用ServerSocket的accept()方法与客户端建立连接
11 Socket client = serverSocket.accept();
12 // 针对每一个客户端请求创建一个线程进行连接管理
13 Thread thread = new Thread(() -> {
14 try {
15 // 获取当前连接的客户端所在端口号
16 int port =client.getPort();
17 System.out.println("与端口号为"+port+"的客户端连接成功!");
18 OutputStream os = client.getOutputStream();
19 os.write(("服务器端向客户端做出响应!").getBytes());
20 Thread.sleep(5000);
21 System.out.println("结束与客户端数据交互");
22 // 关闭流和Socket连接
23 os.close();
24 client.close();
25 } catch (Exception e) {
26 e.printStackTrace();
27 }
28 });
29 // 执行线程类,与客户端进行数据交互
30 thread.start();
31 }
32 }
33 }
文件1中,使用多线程的方式创建了一个服务器端程序。通过在while循环中调用accept()方法,持续接收客户端发送的请求,当与客户端建立连接后,就会为每个客户端开启一个新的线程,每个线程都会与一个客户端建立一对一连接,从而进行数据交互。
为了验证服务器端程序是否实现了多线程,首先运行服务端程序(文件1),之后连续运行三个客户端程序(上一节中的文件2)来与启动的服务端建立连接进行数据交互。在测试过程中,当运行第一个客户端程序时,服务端马上就进行数据处理,打印出“与端口号为56016的客户端连接成功!”的信息(端口号是随机的,可能不同),紧接着再运行第二、和第三个客户端程序,会发现服务端也立刻做出回应,同时这启动的三个客户端也能够接收到服务端响应的信息,如图2所示。
图2 运行结果
从图2可以看出,程序通过多线程的方式,实现多个用户同时对同一个服务器端程序的访问。