当前位置: 首页 > news >正文

Java 实现 TCP 一发一收通信

在网络编程中,TCP(传输控制协议)凭借其可靠传输的特性,成为需要确保数据完整性场景的核心选择。本文将基于一段 Java 代码实例,全面解析 TCP 单向通信的实现逻辑,帮助开发者掌握 TCP 编程的基础框架与底层原理。

核心代码展示

以下是实现 TCP 单向通信的完整代码,包含客户端与服务器端两个部分:

客户端(Client)代码

package com.practical.agreement.tcp.tcp_1;
import java.io.OutputStream;
import java.net.Socket;
import java.io.DataOutputStream;
/*
@description:
@ClassName Client
@author chen
@create 2025-07-21 14:53
@Version 1.0
*/
public class Client
{public static void main(String[] args) throws Exception{// 1、创建Socket对象,并同时请求与服务端程序的连接。Socket socket = new Socket("127.0.0.1", 8888);// 2、从socket通信管道中得到一个字节输出流,用来发数据给服务端程序。OutputStream os = socket.getOutputStream();// 3、把低级的字节输出流包装成数据输出流DataOutputStream dos = new DataOutputStream(os);// 4、开始写数据出去了dos.writeUTF("发送数据----~~~~~~~");dos.close();// 5、释放连接资源socket.close(); // 释放连接资源}
}

服务器端(Server)代码

package com.practical.agreement.tcp.tcp_1;
import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
@description:
@ClassName Server
@author chen
@create 2025-07-21 14:54
@Version 1.0
*/
public class Server
{public static void main(String[] args) throws Exception{System.out.println("-----服务端启动成功-------");// 1、创建ServerSocket的对象,同时为服务端注册端口。ServerSocket serverSocket = new ServerSocket(8888);// 2、使用serverSocket对象,调用一个accept方法,等待客户端的连接请求Socket socket = serverSocket.accept();// 3、从socket通信管道中得到一个字节输入流。InputStream is = socket.getInputStream();// 4、把原始的字节输入流包装成数据输入流DataInputStream dis = new DataInputStream(is);// 5、使用数据输入流读取客户端发送过来的消息String rs = dis.readUTF();System.out.println(rs);// 其实我们也可以获取客户端的IP地址System.out.println(socket.getRemoteSocketAddress());dis.close();socket.close();}
}

一、TCP 协议基础与代码功能解析

TCP 是一种面向连接的可靠传输协议,其核心特性体现在:

  • 连接导向:通信前必须通过 "三次握手" 建立连接
  • 可靠传输:通过序列号、确认应答、超时重传等机制保证数据完整
  • 流量控制:通过滑动窗口机制避免接收方缓冲区溢出
  • 拥塞控制:根据网络状况动态调整发送速率

本次展示的代码实现了 TCP 最基础的单向通信模式:客户端主动发起连接并发送一条字符串消息,服务器端接收消息后打印内容及客户端地址信息。该代码虽简单,却完整包含了 TCP 通信的核心流程,是理解复杂 TCP 应用的基础。

二、代码执行流程深度解析

1. 服务器端启动与等待连接

服务器端的运行遵循 "初始化 - 等待 - 处理" 的逻辑:

  1. 端口注册:通过new ServerSocket(8888)创建服务器端对象,同时向系统注册 8888 端口,用于监听客户端连接请求
  2. 阻塞等待:serverSocket.accept()方法会进入阻塞状态,直到有客户端发起连接请求,此时返回一个Socket对象,建立与客户端的专属通信管道
  3. 流初始化:从Socket中获取字节输入流InputStream,并包装为DataInputStream—— 这种包装能直接读取 Java 基本数据类型,简化字符串传输流程
  4. 数据读取:dis.readUTF()方法读取客户端发送的 UTF-8 编码字符串,该方法会严格按照writeUTF()的编码格式解析数据
  5. 资源释放:读取完成后关闭输入流和Socket,释放系统资源

2. 客户端连接与数据发送

客户端的执行流程体现了 TCP 的主动发起特性:

  1. 建立连接:new Socket("127.0.0.1", 8888)通过指定 IP 地址(本地回环地址)和端口号,向服务器端发起连接请求,底层会完成三次握手过程
  2. 输出流准备:获取Socket的字节输出流OutputStream,并包装为DataOutputStream,便于使用writeUTF()方法发送字符串
  3. 消息发送:dos.writeUTF()会先写入字符串长度(2 字节),再写入 UTF-8 编码的字节序列,确保服务器端能准确解析
  4. 连接关闭:发送完成后关闭输出流和Socket,触发四次挥手过程终止连接

三、TCP 通信的关键特性验证

通过代码运行可直观观察 TCP 的核心特性:

  • 连接导向:若先启动客户端会抛出Connection refused异常,证明必须先建立连接才能通信
  • 顺序传输:多次发送消息时(需修改代码为循环),服务器端接收顺序与发送顺序完全一致
  • 可靠交付:在网络不稳定环境下,TCP 会自动重传丢失的数据包,确保服务器端最终能完整接收

代码中socket.getRemoteSocketAddress()方法展示了 TCP 的双向地址感知能力,该方法返回客户端的 IP 地址和端口号(格式为/127.0.0.1:端口号),体现了 TCP 连接的端到端特性。

四、技术局限性与扩展方向

现有代码的局限性

  1. 单向通信:仅支持客户端向服务器端发送消息,无法实现双向交互
  2. 单连接处理:服务器端处理完一个连接后即关闭,无法同时服务多个客户端
  3. 无异常处理:未包含try-catch块,网络波动可能导致程序崩溃
  4. 资源释放问题:直接关闭流可能导致资源释放不彻底,建议使用 try-with-resources 语法

实用扩展方案

  1. 双向通信:在客户端添加输入流、服务器端添加输出流,实现消息互发
  2. 多客户端支持:使用多线程技术,主线程负责接收连接,子线程处理具体通信
  3. 异常处理增强:添加try-catch-finally块捕获IOException,确保资源正确释放
  4. 长连接保持:去除单次通信后关闭连接的逻辑,通过心跳机制维持长连接

五、TCP 通信的典型应用场景

尽管 TCP 存在连接建立延迟、开销较大等特点,但其可靠性使其在以下场景中不可替代:

  • 文件传输:FTP、SFTP 等协议基于 TCP 实现,确保文件传输完整
  • 金融交易:银行转账、支付系统等需保证交易指令准确无误
  • 邮件服务:SMTP、IMAP 等邮件协议依赖 TCP 确保邮件不丢失
  • HTTP 通信:网页浏览、API 调用等场景需要完整的内容传输

相比之下,视频通话、实时游戏等对延迟敏感的场景更适合 UDP,开发者需根据业务特性选择合适的传输协议。

总结

本文通过一段精简的 Java 代码,完整呈现了 TCP 单向通信的实现过程。从服务器端的端口监听,到客户端的连接发起,再到数据的编码传输,每一步都体现了 TCP 协议的核心设计思想。

掌握这段代码的原理后,开发者可逐步扩展出更复杂的 TCP 应用 —— 无论是多客户端聊天系统,还是文件传输工具,其底层都离不开本文阐述的基础流程。理解 TCP 的可靠性机制与代码实现的对应关系,是构建稳定网络应用的关键。

http://www.lryc.cn/news/595328.html

相关文章:

  • 力扣面试150题--搜索二维矩阵
  • A316-Mini-V1:超小尺寸USB高清音频解码器模组技术探析
  • 解决 Ant Design v5.26.5 与 React 19.0.0 的兼容性问题
  • macOS 上安装 Kubernetes(k8s)
  • React 中使用immer修改state摆脱“不可变”
  • Ubuntu安装k8s集群入门实践-v1.31
  • HOT100——图篇Leetcode207. 课程表
  • Redis入门教程(一):基本数据类型
  • (LeetCode 每日一题) 1957. 删除字符使字符串变好 (字符串)
  • 17 BTLO 蓝队靶场 Pretium 解题记录
  • 【C++11】哈希表与无序容器:从概念到应用
  • 【Unity基础】Unity中2D和3D项目开发流程对比
  • 用户虚拟地址空间布局架构
  • git_guide
  • 【Git#6】多人协作 企业级开发模型
  • 【面经】实习经历
  • 深入理解 C++ 中的指针与自增表达式:*a++、(*a)++ 和 *++a 的区别解析
  • 破除扫描边界Photoneo MotionCam-3D Color 解锁动态世界新维度
  • 京东疯狂投资具身智能:众擎机器人+千寻智能+逐际动力 | AI早报
  • 2021 RoboCom 世界机器人开发者大赛-本科组(复赛)解题报告 | 珂学家
  • [硬件电路-64]:模拟器件 -二极管在稳压电路中的应用
  • 物流链上的智慧觉醒:Deepoc具身智能如何重塑搬运机器人的“空间思维”
  • 库卡气体保护焊机器人省气的方法
  • Java IO流体系详解:字节流、字符流与NIO/BIO对比及文件拷贝实践
  • 大模型高效适配:软提示调优 Prompt Tuning
  • 【Windows】多标签显示文件夹
  • PLC之间跨区域通讯!无线通讯方案全解析
  • SQL通用增删改查
  • Spring Cache 扩展:Redis 批量操作优化方案与 BatchCache 自定义实现
  • C++中的deque容器