在上一小节中,分别实现了服务器端程序和客户端程序,当一个客户端程序请求服务器端时,服务器端就会结束阻塞状态,完成程序的运行。实际上,很多服务器程序都是允许被多个应用访问的,例如门户网站可以被多个用户同时访问,因此服务器都是多线程的。下面通过一个图例来表示多个用户访问同一个服务器,如下所示:
    image.png
    上图中代表的是多个客户端访问同一个服务器端,服务器端为每个客户端创建一对应的 Socket,并且开启一个新的线程使两个 Socket 建立专线进行通信。接下来根据上图所示的通信方式上一小节的程序进行改进,如下所示:

    1. import java.io.OutputStream;
    2. import java.net.*;
    3. public class Server {
    4. public static void main(String[] args) throws Exception {
    5. //创建 TCPServer 对象,并调用 listen()方法
    6. new TCPServer().listen();
    7. }
    8. }
    9. //TCPServer 服务端
    10. class TCPServer{
    11. private static final int PORT = 7788; //定义一个端口号
    12. public void listen() throws Exception {
    13. //创建 ServerSocket 对象,监听指定的端口
    14. ServerSocket serverSocket = new ServerSocket(PORT);
    15. while (true) {
    16. //调用 ServerSocket 的 accept()方法与客户端建立连接
    17. final Socket client = serverSocket.accept();
    18. //开启一个新线程
    19. new Thread() {
    20. @Override
    21. public void run() {
    22. super.run();
    23. //定义一个输出流对象
    24. OutputStream os;
    25. try {
    26. os = client.getOutputStream(); //获取客户端的输出流
    27. System.out.println("开始和客户端交互数据");
    28. os.write("我爱你".getBytes());
    29. Thread.sleep(5000); //使线程休眠 5000 毫秒
    30. System.out.println("结束和客户端交互数据");
    31. client.close();
    32. os.close();
    33. } catch (Exception e) {
    34. e.printStackTrace();
    35. }
    36. }
    37. }.start();
    38. }
    39. }
    40. }

    上述代码块中使用多线程的方式创建了一个服务器端程序。通过在 while 循环中调用 accept()方法,不停的接收客户端发送的请求,当与客户端建立连接后,就会开启一个新的线程,该线程会去处理客户端发送的数据,而主线程仍继续等待状态。

    为了验证服务器端程序时候实现了多线程,首先运行服务器端程序,之后运行三个客户端程序,当运行第一个客户端程序时,服务器马上就进行数据处理,打印出“开始于客户端交互数据”,在运行第 2 个和第 3 个客户端程序,会发现服务端也立刻做出回应,3 个客户端会话结束后分别打印各自的结束消息,如下图所示。这说明通过多线程的方式可以实现多个用户对同一个服务器的访问。
    image.png