Java的I/O操作主要分为三种类型:OIO(同步阻塞I/O)、NIO(同步非阻塞I/O)和AIO(异步非阻塞I/O)。其中,OIO与NIO最核心的区别在于数据处理方式的不同:OIO是基于流的,而NIO是基于缓冲区的。在OIO模型中,数据以流的形式逐字节读取,只能顺序访问,无法随意定位或回退。一旦读取完成,数据便不再保留;若需重复处理或反向访问,必须将数据先存储到临时缓冲区中。相比之下,NIO将数据首先读入缓冲区,程序可以在缓冲区中灵活地前移或后退,便于多次访问和处理。这种机制提升了数据操作的自由度和效率。然而,使用缓冲区也带来了一些挑战:必须判断缓冲区中是否已完整读取所需数据,同时在新数据写入时,要防止覆盖尚未处理的原有内容,因此需要合理管理读写位置和数据状态。这种设计虽然提高了性能和可控性,但也对开发者的逻辑控制提出了更高要求。整体而言,从OIO到NIO的转变体现了Java I/O从简单流式处理向高效缓冲机制的演进。
1、 采用OIO编写简易客户端程序,代码实现如下所示。
2、 创建一个名为 OIOServer 的 Java 类,用于实现一个基于传统 I/O 模型的网络服务器程序。该程序监听指定端口,接收客户端连接,并对客户端发送的数据进行响应处理。整个过程采用多线程机制,以支持多个客户端同时连接。
3、 程序入口为 main 方法,首先实例化一个 ServerSocket 对象,绑定端口号 10010,表示服务器将在该端口上等待客户端的连接请求。随后输出提示信息服务器启动成功,表明服务已正常运行。进入一个无限循环,持续调用 accept 方法等待客户端接入。该方法在没有客户端连接时会处于阻塞状态,直到有新的连接到来。
4、 每当有客户端成功建立连接,accept 方法将返回一个 Socket 对象,代表与该客户端的通信通道。此时程序会打印来了一个新的客户端提示信息,并将该 Socket 封装成一个任务,提交给线程池执行。线程池通过 Executors 的 newCachedThreadPool 方法创建,具备动态创建和回收线程的能力,适合处理大量短生命周期的任务。
5、 每个客户端连接由独立线程处理,具体逻辑封装在 handler 方法中。该方法接收一个 Socket 参数,通过其输入流读取客户端发送的数据,输出流向客户端回传响应内容。为方便字符串操作,还引入了 PrintWriter 对象,用于向输出流写入格式化文本。
6、 在 handler 方法内部,定义一个固定大小的字节数组作为缓冲区,用于暂存从输入流中读取的数据。通过 getInputStream 方法获取输入流对象,调用其 read 方法读取数据到缓冲区。此操作为阻塞式,若当前无数据可读,线程将暂停执行,直至数据到达或连接关闭。
7、 若 read 方法返回 -1,则表示客户端已关闭连接,输入流结束,此时跳出循环,进入资源释放流程。无论通信是否正常结束,最终都会执行 finally 块中的代码,尝试关闭 Socket 连接,避免资源泄露。若关闭过程中出现异常,将其堆栈信息打印出来以便排查问题。
8、 整个服务端设计基于经典的一请求一线程模型,虽然能实现并发处理,但每个连接都对应一个独立线程,当并发量增大时,系统可能因线程数量过多而导致性能下降甚至崩溃。此外,大量线程在无数据传输时处于阻塞状态,造成资源浪费。相比之下,NIO 等非阻塞 I/O 模型可借助选择器机制,用少量线程管理大量连接,更适合高并发场景。
9、 程序中使用 GBK 编码进行字符转换,适用于中文环境下的文本传输,但需确保客户端和服务端编码一致,否则可能出现乱码。PrintWriter 默认不会自动刷新,因此在发送响应后手动调用 flush 方法,保证消息即时发出。
10、 该服务器不具备主动断开机制,依赖客户端正常关闭连接来终止会话。若客户端异常退出或网络中断,可能造成服务端线程长时间挂起,影响资源回收。实际应用中可考虑加入超时机制或心跳检测,提升系统的健壮性。
11、 整体结构清晰,逻辑完整,适合作为学习 Java 网络编程的基础示例,帮助理解 Socket 通信的基本流程、多线程协作以及 I/O 操作的核心概念。尽管存在性能瓶颈,但在低并发、低延迟要求的场景下仍具有实用价值。通过扩展功能,如加入协议解析、数据加密、日志记录等模块,可逐步演变为功能完备的网络服务组件。
12、 使用telnet工具对目标进行连接测试操作
13、 按下Win键和R键,打开运行对话框。
14、 打开命令提示符,输入cmd并确认。在窗口中键入telnet 127.0.0.1 10010,回车执行。接着按下Ctrl + ] 组合键,即可进入指定操作界面。
15、 连接失败,请检查telnet服务是否已启用。
16、 请确认已开启下图中的Telnet客户端功能。
17、 发消息
18、 通过telnet发送命令:send hello。
19、 服务端控制台成功输出了hello信息。
