JavaEE 编写Java程序,实现简单的echo程序(网络编程TCP实践练习)

server/2025/2/27 6:25:39/

Java TCP 客户端/服务器开发深度解析

一、客户端代码全注释

java">public class TcpClient {private Socket socket = null;  // TCP通信核心对象// 构造函数:建立TCP连接public TcpClient(String ip, int port) throws IOException {// 创建Socket时会自动进行三次握手socket = new Socket(ip, port);  // 参数1: 服务器IP  参数2: 端口号}public void start() throws IOException {System.out.println("客户端启动");// try-with-resources 自动关闭资源try (InputStream in = socket.getInputStream();   // 接收数据的字节流OutputStream out = socket.getOutputStream(); // 发送数据的字节流Scanner scannerConsole = new Scanner(System.in); // 控制台输入Scanner scannerIn = new Scanner(in)) {      // 网络输入解析while (true) {// 1. 控制台输入处理System.out.print("-> ");String request = scannerConsole.next();  // 阻塞等待用户输入// 2. 发送请求到服务器PrintWriter printWriter = new PrintWriter(out); // 包装输出流printWriter.println(request);  // 自动添加换行符printWriter.flush();           // 强制立即发送缓冲区内容// 3. 接收服务器响应if (!scannerIn.hasNext()) break; // 检测连接是否关闭String response = scannerIn.next();System.out.println("服务器响应: " + response);}} // 自动关闭所有资源:socket、流、Scanner}
}

客户端核心三要素:

  1. 连接建立:通过new Socket()完成TCP三次握手
  2. 数据通道
    • getInputStream()获取接收数据流
    • getOutputStream()获取发送数据流
  3. 资源管理:使用try-with-resources自动释放连接

二、服务器代码全注释

java">public class TcpServer {private ServerSocket serverSocket = null;  // 服务端监听套接字// 初始化服务器public TcpServer(int port) throws IOException {serverSocket = new ServerSocket(port); // 绑定指定端口System.out.println("服务器监听端口: " + port);}public void start() throws IOException {System.out.println("启动服务器主线程");while (true) {// 阻塞等待客户端连接(核心方法)Socket clientSocket = serverSocket.accept(); System.out.println("检测到新连接");// 为每个客户端创建独立线程new Thread(() -> {try {processConnection(clientSocket); // 处理客户端业务} catch (IOException e) {e.printStackTrace();}}).start();}}// 处理单个客户端连接private void processConnection(Socket clientSocket) throws IOException {// 获取客户端地址信息String clientInfo = String.format("[%s:%d]", clientSocket.getInetAddress(), clientSocket.getPort());try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {Scanner scanner = new Scanner(inputStream);System.out.println(clientInfo + " 客户端上线");while (scanner.hasNext()) {  // 持续监听客户端请求// 1. 读取请求String request = scanner.next();// 2. 处理业务逻辑String response = process(request); // 3. 返回响应PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);printWriter.flush();  // 确保数据立即发送System.out.println(clientInfo + " 处理请求: " + request);}}System.out.println(clientInfo + " 客户端下线");}// 业务处理(示例直接返回原字符串)private String process(String request) {return request.toUpperCase(); // 示例:转为大写}
}

服务器核心三要素:

  1. 端口监听ServerSocket绑定指定端口
  2. 连接接收accept()方法阻塞等待连接
  3. 并发处理:为每个客户端创建独立线程

三、关键方法深度解析

3.1 accept()方法详解

java">Socket clientSocket = serverSocket.accept();
  • 阻塞特性:在没有客户端连接时,线程会在此处挂起
  • 返回对象:返回的Socket对象包含:
    • 客户端IP地址(getInetAddress()
    • 客户端端口(getPort()
    • 新的数据通道(输入/输出流)
  • 并发基础:每次accept返回新的Socket,实现多客户端处理

3.2 flush()的必要性

java">printWriter.flush();
场景无flush有flush
数据传输时机缓冲区满时自动发送立即强制发送
适用场景大数据量传输需要实时交互的场景
风险点数据可能长时间滞留增加网络包数量

缓冲区原理

客户端内存:[数据1][数据2][数据3] → 缓冲区填满后自动发送
手动flush: [数据1] → 立即发送 → [数据2] → 立即发送

四、TCP核心组件对比

4.1 ServerSocket vs Socket

特性ServerSocketSocket
用途服务端监听端口建立实际数据通道
创建时机服务启动时创建accept()成功后自动创建
生命周期整个服务运行期间存在单个连接周期内存在
主要方法accept(), bind(), close()getInputStream(), close()

4.2 TCP通信全流程

客户端 服务器 SYN SYN-ACK ACK 三次握手完成 发送数据(request) 返回响应(response) FIN ACK FIN ACK 四次挥手断开 客户端 服务器

五、IntelliJ多实例运行配置

5.1 配置步骤演示

  1. 打开运行配置
    Run -> Edit Configurations
    
  2. 启用多实例
    选择客户端配置 -> Modify options -> Allow multiple instances
    
  3. 运行效果
    可以同时启动多个客户端进程
    每个进程独立连接到服务器
    

5.2 实现原理

  • JVM进程隔离:每个客户端运行在独立JVM中
  • 端口重用:客户端使用临时端口(1024-65535)
  • 服务端设计
    java">new Thread(() -> processConnection(clientSocket)).start();
    
    每个连接使用独立线程处理

六、最佳实践建议

  1. 资源关闭顺序

    java">// 正确关闭顺序示例
    try (Socket socket = new Socket(...);OutputStream out = socket.getOutputStream();InputStream in = socket.getInputStream()) {// 使用资源
    } // 自动反向关闭:in -> out -> socket
    
  2. 异常处理规范

    java">catch (IOException e) {System.err.println("连接异常: " + e.getMessage());// 需要手动关闭资源try {if (socket != null) socket.close();} catch (IOException ex) {ex.printStackTrace();}
    }
    
  3. 性能优化技巧

    • 使用线程池代替裸线程
    • 设置合理的Socket超时时间
    • 采用NIO非阻塞模式处理高并发

通过深入理解TCP通信机制和Java网络API的实现原理,开发者可以构建出稳定高效的网络应用程序。多线程服务器的设计需要特别注意资源竞争和线程安全问题,在实际生产环境中建议使用ExecutorService等高级并发工具进行线程管理。


http://www.ppmy.cn/server/170956.html

相关文章

20250221 NLP

1.向量和嵌入 https://zhuanlan.zhihu.com/p/634237861 encoder的输入就是向量,提前嵌入为向量 二.多模态文本嵌入向量过程 1.文本预处理 文本tokenizer之前需要预处理吗? 是的,文本tokenizer之前通常需要对文本进行预处理。预处理步骤可…

深度学习批次数据处理的理解

基础介绍 在计算机视觉深度学习网络中,在训练阶段数据输入通常是一个批次,即不是一次输入单张图片,而是一次性输入多张图片,而神经网络的结构内部一次只能处理一张图片,这时候很自然就会考虑为什么要这样的输入&#…

xenomai4的dovetail学习(2)——oob和中断管理

文章目录 OUT-OF-BAND启用和禁用stage升级oob中断通知oob irq进入/退出evl禁用/启用CPU中断禁用/启用oob中断oob的IPI(Inter-Processor Interrupt)注入IRQ拓展 IRQ work API OUT-OF-BAND启用和禁用 在将中断送到带外处理程序之前,需要启用oo…

QT中日志的使用案例 || 自动创建、管理、保存QT日志数据

目录 1.quiwidget.cpp 2.widget.cpp 3.widget.h 4.在需要记录日志的地方直接将信息插入即可 1. 释放 m_fileLog 和 m_textStream 1.1 为什么要关闭和删除 m_fileLog 和 m_textStream? 1.2 如果不这样做会有什么坏处? 3. 总结 4.参考文章 需求分析…

陀螺匠·企业助手v1.8 产品介绍

陀螺匠企业助手是一套采用Laravel 9框架结合Swoole高性能协程服务与Vue.js前端技术栈构建的新型智慧企业管理与运营系统。该系统深度融合了客户管理、项目管理、审批流程自动化以及低代码开发平台,旨在为企业提供一站式、数字化转型的全方位解决方案,助力…

保姆级! 本地部署DeepSeek-R1大模型 安装Ollama Api 后,Postman本地调用 deepseek

要在Postman中访问Ollama API并调用DeepSeek模型,你需要遵循以下步骤。首先,确保你有一个有效的Ollama服务器实例运行中,并且DeepSeek模型已经被加载。 可以参考我的这篇博客 保姆级!使用Ollama本地部署DeepSeek-R1大模型 并java通过api 调用 具体的代码实现参考我这个博…

Touchgfx控件 BOX和textArea

(一)BOX 是TouchGFX中最轻量级的控件之一,因为它不需要读取任何像素数据或进行任何复杂计算。 因此,大部分平台会将方框视为非常快速的控件。特性如下: (1)一般用来显示背景或者覆盖。 (2)不会产…

AOP进阶-05.连接点

一.连接点 JoinPoint有两个,要使用org,aspectj.lang package com.gjw.aop;import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org…