Skip to content

Latest commit

 

History

History
256 lines (169 loc) · 9.34 KB

README-CH.md

File metadata and controls

256 lines (169 loc) · 9.34 KB

TCP 服务器-客户端模拟与线程池与队列机制

概述

这个项目模拟了一个 TCP 服务器-客户端系统,其中服务器使用线程池来处理多个客户端的连接。服务器通过队列机制管理等待中的客户端,当达到最大并发连接数时,使用超时处理机制丢弃超过最大等待时间的客户端连接。

特性:

  • TCP 服务器:处理多个客户端的连接,最多支持 2 个客户端并发。
  • 线程池:服务器使用 ThreadPoolExecutor 来管理客户端处理线程。
  • 队列管理:当达到最大连接数时,客户端会被放入等待队列,直到有空闲线程可用。
  • 超时处理:等待队列中的客户端如果超过指定等待时间(6 秒),会被丢弃。

项目结构

  • TcpServer.java:服务器端代码,负责处理客户端连接、线程池管理和等待队列的操作。
  • TcpClient1.java:客户端 1 代码,连接到服务器,发送消息并接收响应。
  • TcpClient2.java:客户端 2 代码,连接到服务器,发送消息并接收响应。
  • TcpClient3.java:客户端 3 代码,连接到服务器,发送消息并接收响应。

TcpServer 详细说明

特性

  • 线程池:服务器使用 ThreadPoolExecutor 来处理最大 2 个并发客户端。
    • MAX_CLIENTS:服务器最多同时处理的客户端数量(设置为 2)。
    • WAIT_TIME:客户端在等待队列中等待的最大时间(单位:秒),超时则丢弃该连接。
  • 客户端处理:每个客户端由一个独立的线程(ClientHandler)来处理,处理客户端的请求并发送响应。
  • 等待队列:当服务器达到最大连接数时,新的客户端连接会被放入等待队列中。
    • 服务器会定期检查队列中的客户端,并在有空闲线程时开始处理队列中的客户端。
    • 如果客户端等待超过了 WAIT_TIME 设置的最大时间,连接将被丢弃。

工作流程

  1. 服务器初始化
    • 服务器监听端口 8888,等待客户端连接。
    • 如果当前活跃连接数少于 MAX_CLIENTS,服务器会立即处理新的客户端连接。
    • 如果活跃连接数已满,则新的客户端会被放入等待队列。
  2. 客户端处理
    • 服务器与客户端进行通信,读取客户端发送的消息,并发送适当的响应。
    • 处理完请求后,服务器会发送 END 消息,表示通信结束。
  3. 等待机制
    • 当服务器无法立即处理客户端时,客户端会进入等待队列。
    • 服务器每 100 毫秒检查一次队列,看看是否有空闲线程可以处理等待中的客户端。
    • 如果客户端等待时间超过了 WAIT_TIME,则服务器会丢弃该连接。
  4. 超时处理
    • 如果客户端在等待队列中的等待时间超过了 WAIT_TIME,连接会被丢弃,并会在控制台输出超时信息。

当服务器线程池已满(2 个客户端连接)时:

  • 客户端 3 的处理

    • 当服务器的线程池已经有 2 个客户端连接时,客户端 3 将被放入等待队列中,直到有空闲线程。
    • 如果客户端 3 在队列中等待超过 WAIT_TIME(即 6 秒),则会被丢弃,并会在控制台输出超时信息。
    • 如果客户端 3 在等待期间有空闲线程可用,服务器会从队列中取出客户端并开始处理。

TcpClient1、TcpClient2、TcpClient3 详细说明

特性

  • 连接超时:客户端在尝试连接服务器时设置了 3 秒的超时限制。
  • 消息发送:客户端发送固定消息给服务器。
  • 监听响应:客户端会一直监听服务器的响应,直到收到 END 消息。

工作流程

  1. 连接服务器
    • 客户端连接到服务器,服务器地址默认为 localhost:8888
  2. 发送消息
    • 客户端向服务器发送消息 "我是客户端1"(或 "我是客户端2""我是客户端3")。
  3. 接收服务器响应
    • 客户端持续监听服务器的响应。如果收到 END 消息,客户端将退出。
  4. 关闭连接
    • 一旦通信结束,客户端会关闭与服务器的连接。

如何运行

  1. 编译 Java 文件

    • 确保 TcpServer.javaTcpClient1.javaTcpClient2.javaTcpClient3.java 文件位于同一目录下。

    • 打开终端,导航到文件所在目录。

    • 编译 Java 文件:

      javac TcpServer.java
      javac TcpClient1.java
      javac TcpClient2.java
      javac TcpClient3.java
  2. 启动服务器

    • 在终端中运行以下命令启动服务器:

      java TcpServer
    • 服务器将开始监听端口 8888,等待客户端连接。

  3. 启动客户端

    • 在另一个终端中运行客户端:

      java TcpClient1
      java TcpClient2
      java TcpClient3
    • 客户端将连接到服务器并发送消息。


配置说明

  • 端口:服务器监听的端口为 8888
  • 最大客户端数:服务器最多同时处理 2 个客户端连接。
  • 等待时间:客户端在等待队列中的最大等待时间为 6 秒,超过该时间后会被丢弃。

示例输出

服务器端:

===========这是一个mysql服务器模拟===========
服务器启动,等待客户端连接...
当前连接数已满,客户端进入等待队列...
等待空闲处理槽...
等待空闲处理槽...
等待空闲处理槽...
等待空闲处理槽...

客户端:

连接到服务器...
已发送消息: 我是客户端1
服务器响应: 服务器已收到您的消息。
正在处理客户端请求...
服务器响应: 服务器已收到您的消息:我是客户端1,处理完毕。
接收到结束通信标志,客户端即将退出。

超时情况(客户端 3):

如果客户端 3 等待时间超过 6 秒,则会出现以下消息:

当前连接数已满,客户端进入等待队列...
等待空闲处理槽...
等待空闲处理槽...
连接请求超时,丢弃客户端连接: /127.0.0.1

客户端 3 成功处理:

如果客户端 3 在等待期间有线程空闲,成功从队列中取出并处理,则输出如下:

当前连接数已满,客户端进入等待队列...
等待空闲处理槽...
等待空闲处理槽...
正在处理客户端请求...
服务器响应: 服务器已收到您的消息:我是客户端3,处理完毕。
接收到结束通信标志,客户端即将退出。

注意事项

  • 服务器使用 LinkedBlockingQueue 来管理等待队列和客户端连接。
  • 服务器的 ThreadPoolExecutor 确保最多只有 MAX_CLIENTS 客户端被并发处理,等待队列提供了有序的客户端连接管理。
  • 连接超时机制确保当客户端等待过久时,会自动丢弃该连接,避免资源浪费。

如果没有线程池会发生什么?

如果没有线程池,服务器需要为每一个客户端连接创建一个独立的线程来处理。这种情况下可能会导致以下问题:

1. 线程开销过大

  • 每次有一个新的客户端连接时,服务器都会创建一个新的线程。
  • 线程的创建和销毁是有成本的,包括内存分配和 CPU 时间的消耗。
  • 如果客户端连接数很多,会导致大量的线程被创建,增加了系统的资源开销。

2. 资源耗尽

  • 线程数量是有限的,如果客户端连接数非常多,服务器可能会耗尽线程资源或超出操作系统对线程数量的限制。
  • 这可能导致服务器无法响应新的客户端连接,甚至引发服务器崩溃。

3. 上下文切换频繁

  • 操作系统需要为每个线程分配时间片,如果线程数量过多,CPU 会频繁进行线程的上下文切换。
  • 上下文切换会带来性能损耗,导致实际的处理效率下降。

4. 无法控制并发数量

  • 没有线程池的情况下,服务器无法限制并发处理的客户端数量。
  • 如果突然有大量的客户端连接,服务器可能因为资源不足而被压垮。

5. 代码复杂性增加

  • 服务器需要手动管理每个线程的生命周期,包括处理线程终止、异常等情况

  • 代码的复杂性和维护成本会增加。


使用线程池的优势

线程池能够有效避免上述问题:

  1. 线程复用

    • 线程池会重复使用已经创建的线程,而不是为每个客户端创建新线程,从而减少了线程创建和销毁的开销。
  2. 限制并发

    • 线程池可以通过设置最大线程数量来限制同时处理的客户端数量,避免资源耗尽。
  3. 避免频繁切换

    • 通过限制线程数量,减少了线程之间的上下文切换,提高了处理效率。
  4. 简化管理

    • 线程池自动管理线程的生命周期,开发者无需手动处理线程的创建和销毁,简化了代码逻辑。

总结

如果没有线程池,服务器的并发性能会受到严重影响,可能会因为资源耗尽而导致崩溃。而线程池能够通过限制并发数量、复用线程和减少开销,显著提高服务器的性能和稳定性。因此,在需要处理大量客户端连接的情况下,线程池是服务器开发中的一个最佳实践。

许可证

该项目采用 MIT 许可证