Java 网络编程入门:手把手实现两个程序之间的 TCP 对话
在学习 Java 网络编程时我们会接触 IP 地址、端口号、TCP、UDP、Socket、输入流和输出流等概念。如果只看定义这些知识很容易显得抽象。这些定义的详细解释在我上上篇博客中其实已经进行了比较详细的解释如果还不是很了解的小伙伴可以移步这篇文章计算机网络基础TCP、UDP、IP、端口号与套接字先进行了解我也会在文章的第一节对这些基础知识进行简单的解释。本文将从一个具体目标出发编写两个独立的 Java 程序让它们建立 TCP 连接并在控制台中互相发送消息。这个程序在后续也会不断的完善在此过程中将持续更新博客感兴趣的话可以持续关注一、网络编程基础概念1.1 什么是网络编程网络编程就是让不同的程序通过网络交换数据。这些程序可以在不同的计算机上也可以像文本一样先在同一台计算机上进行测试。一次网络通信至少需要解决三个问题对方在哪台计算机上数据应该交给这台计算机中的哪个程序双方按照什么规则传输和解释数据对应的基础概念分别是IP 地址定位计算机端口号定位计算机中的程序网络协议规定双方通信的规则。1.2 什么是输入流和输出流连接建立以后双方通过流收发数据InputStream read() 接收数据 OutputStream write() 发送数据输入和输出是站在当前程序的角度定义的数据进入当前程序 输入 数据离开当前程序 输出所以两边流的对应关系是A 的 OutputStream → B 的 InputStream B 的 OutputStream → A 的 InputStream二、从零实现两个 Java 程序的 TCP 对话前面已经介绍过 IP、端口号、TCP、Socket 等基础概念。现在开始进行代码的实现过程。首先我们明确最终要实现的效果为A 程序输入消息 ↓ A 将消息发送给 B ↓ B 在控制台打印消息 ↓ B 输入回复 ↓ B 将回复发送给 A ↓ A 在控制台打印回复在进行下面步骤之前首先要在Maven下创建项目然后创建两个类在这里为了方便表示直接将他们命名为A.java和B.java2.1 第一步让 B 监听端口并等待 A 连接2.1.1 创建 ServerSocket 并监听 54321 端口在前面的流程中B 的第一个职责是等待 A 的连接。因此我们先在B.java的main方法中创建一个ServerSocket相关的代码如下所示此行代码就表示当B程序启动之后就会在本机的54321端口上创建了一个服务端。我们可以把它理解为 B 先在本机创建了一个“接待点”地址为127.0.0.1:54321 。之后A 程序只要连接这个地址就能找到 B。但是我们也注意到了写完这行代码之后代码中有红色下划线提示错误这个时候我们需要用try\catch来解决这个问题快捷键为Alt Enter光标放在画线单词上同时需要对变量ss进行初始化解决后的完整代码如下所示public class B { public static void main(String[] args) { ServerSocket ss null; try { ss new ServerSocket(54321); } catch (IOException e) { throw new RuntimeException(e); } } }2.1.2 调用accept( )等待A的连接此处的问题与上面红线的问题一致解决方法也一致不多赘述了解决之后的代码如下所示try { Socket s ss.accept(); } catch (IOException e) { throw new RuntimeException(e); }2.2 第二步 让A主动连接BB 负责等待A 则负责主动发起连接。相关的代码为Socket sc new Socket(127.0.0.1, 54321);这行代码的含义是A 程序尝试连接到IP 地址为127.0.0.1 端口号为 54321 的程序。由于本例中 A 和 B 都运行在同一台电脑上所以使用127.0.0.1 他表示本机。用try\catch解决上述问题后相关代码如下public class A { public static void main(String[] args) { try { Socket sc new Socket(127.0.0.1, 54321); } catch (IOException e) { throw new RuntimeException(e); } } }此时A 和 B 已经建立 TCP 连接不过现在只是连接成功双方还没有发送任何消息。现在我们可以测试一下在两段代码中都加上对应的输出语句注意是要先运行B因为这样才能有对应的端口让A去连接。我就不在此赘述了。2.3 第三步 让A获取输入流、输出流和控制台输入A 连接成功后接下来要完成两件事从控制台获取用户输入的消息将消息发送给 B。首先需要让A能够读取来自B的消息我们用输入流来实现相关的代码如下所示当然啦这个功能需要在try里面实现哦代码的意思为A 通过in读取 B 发来的消息。InputStream in sc.getInputStream();其次我们要让A能给B发去信息我们用输出流来实现相关的代码如下同上注意事项代码的意思为A 通过os向 B 发送消息。OutputStream os sc.getOutputStream();我们还需要让A能够读取控制台中输入的内容相关的代码如下所示。代码的意思为A 通过scanner读取控制台中输入的内容。Scanner scanner new Scanner(System.in);此时A的状态可以表示为控制台输入 ↓ Scanner scanner ↓ A 程序 ↓ OutputStream os ↓ B 程序 B 的回复 ↓ InputStream in ↓ A 程序 ↓ 控制台输出接下来我们先实现A从控制台输入一句话。2.3.1 让 A 能够持续读取控制台输入现在 A 已经拥有in读取 B 发来的消息os向 B 发送消息scanner读取控制台输入。接下来我们需要让 A 在控制台中输入要发送给 B 的内容。由于后面需要不断进行对话所以先使用while (true)将整个聊天过程放入循环中while (true) { System.out.println(请说一个字); String m scanner.nextLine();代码的意思是A 每次先在控制台输出“请说一个字”然后通过scanner读取用户输入的一行内容并保存到变量m中。现在 A 已经可以读取控制台输入但消息还没有发送给 B。接下来需要通过输出流os将消息发送出去。2.3.2 A 先发送消息的长度在发送消息内容之前A需要先把消息的长度发送给B。这样做是为了让B在读取消息的时候知道接下来需要读取多少字符相关的代码为写在刚刚的while循环中int len m.length(); os.write(len);现在A 和 B的通信格式为先发送消息长度再发送消息内容。2.3.3 A 发送消息内容在while循环中继续添加一个for循环用于向B发送信息for (int i 0; i len; i) { os.write(m.charAt(i)); } os.flush();这段代码会依次取出m中的每一个字符并通过输出流发送给 B。os.flush(); 表示将已经写入输出流的数据发送出去。至此A 已经完成了发送消息的操作。接下来A 需要等待 B 的回复。2.3.4 A 等待并读取 B 的回复B在回复消息的时候同样会先发送消息的长度再发送消息内容。因此A在接受消息的时候需要先读取长度相关的代码如下int len1 in.read();// 等待 阻塞 System.out.println(收到消息);当 B 还没有发送回复时程序会停在in.read();这一行等待消息的到来。这也就是注释中“等待 阻塞”的含义当前线程暂时不继续执行直到 B 向 A 发送数据。当 A 读取到 B 发送的消息长度后接下来按照这个长度读取每一个字符for (int i 0; i len1; i) { int m1 in.read(); System.out.print((char) m1); }代码的意思是循环读取len1个字符并将每一个字符打印到 A 的控制台中。这样A 的一次操作就完成了A 输入消息 ↓ A 将消息发送给 B ↓ A 等待 B 回复 ↓ A 打印 B 的回复由于这些代码写在while (true)中因此 A 收到回复后会再次回到System.out.println(请说一个字);继续等待下一次输入。此时 A 中循环部分的完整代码如下while (true) { System.out.println(请说一个字); String m scanner.nextLine(); // 发送的第一个字节是数据的长度 int len m.length(); os.write(len); for (int i 0; i len; i) { os.write(m.charAt(i)); } os.flush(); int len1 in.read();// 等待 阻塞 System.out.println(收到消息); for (int i 0; i len1; i) { int m1 in.read(); System.out.print((char) m1); } System.out.println(); }A 的代码暂时写到这里。下面回到 B让 B 能够接收 A 发来的消息。2.4 第四步让 B 接收 A 的消息并回复B 与 A 建立连接后同样需要获取输入流、输出流和控制台输入工具相关代码如下// 对话 InputStream in s.getInputStream();// 输入流 读取对方的消息 OutputStream os s.getOutputStream();// 输出流 给对方发消息 Scanner scanner new Scanner(System.in);接下来同样使用循环让 B 可以持续接收消息并回复while (true) {B 和 A 的执行顺序不同A先发送消息再等待回复 B先接收消息再输入回复因此B 进入循环后的第一件事是读取 A 发来的消息。2.4.1 B 读取 A 发送的消息长度A 发送消息时第一个发送的数据是消息长度os.write(len);所以 B 需要先读取消息长度int len in.read(); System.out.println(收到消息);例如A 输入helloA 首先发送长度5B 执行int len in.read();后len的值就是5。接下来B 就知道需要继续读取 5 个字符。2.4.2 B 读取并打印 A 的消息内容继续添加以下代码for (int i 0; i len; i) { int m1 in.read();// 接受消息 System.out.print((char) m1);// 转成字符打印 } System.out.println();这段代码会按照刚才读取到的长度逐个读取 A 发送的字符。例如A 发送helloB 的控制台会输出收到消息 hello到这里B 已经可以接收并打印 A 发来的消息。 接下来让 B 在控制台输入回复。2.4.3 B 从控制台读取回复在 B 打印完 A 的消息后添加以下代码System.out.println(请输入消息); String m scanner.nextLine();B 的控制台会显示请输入消息随后等待用户输入。例如B 输入你好那么这段内容会保存到变量m中。接下来B 需要把这段回复发送给 A。2.4.4 B 将回复发送给 AB 发送消息的方式与 A 相同先发送长度再发送每一个字符。相关代码如下int len1 m.length(); os.write(len1); for (int i 0; i len1; i) { os.write(m.charAt(i));// 写字到输入框中 } os.flush();// 点击发送按钮这里int len1 m.length();用于获取 B 回复消息的长度。os.write(len1);先将长度发送给 A。随后通过循环将回复中的每一个字符发送出去for (int i 0; i len1; i) { os.write(m.charAt(i)); }最后os.flush();将消息立即发送给 A。此时B 中循环部分的完整代码如下while (true) { int len in.read(); System.out.println(收到消息); for (int i 0; i len; i) { int m1 in.read();// 接受消息 System.out.print((char) m1);// 转成字符打印 } System.out.println(); System.out.println(请输入消息); String m scanner.nextLine(); int len1 m.length(); os.write(len1); for (int i 0; i len1; i) { os.write(m.charAt(i));// 写字到输入框中 } os.flush();// 点击发送按钮 }至此A 和 B 就可以按照固定顺序持续对话A 输入消息 ↓ A 发送消息给 B ↓ B 接收并打印消息 ↓ B 输入回复 ↓ B 发送回复给 A ↓ A 接收并打印回复 ↓ 进入下一轮对话整个通信过程始终遵循下面的顺序A发送 → 接收 B接收 → 发送因此运行程序时仍然需要先启动 B再启动 A。这样一个基础的通过TCP 对话对话的程序我们就实现了接下来会持续更新哦并且会进一步完善完整代码如下A.javaimport java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.Socket; import java.util.Scanner; // 网络基础知识 // 实现两个程序之间发送消息 public class A { public static void main(String[] args) { // 套接字 try { Socket sc new Socket(127.0.0.1, 54321);// 男方 System.out.println(发起连接~); InputStream in sc.getInputStream(); OutputStream os sc.getOutputStream(); Scanner scanner new Scanner(System.in); while (true) { System.out.println(请说一个字); String m scanner.nextLine(); // 发送的第一个字节是数据的长度 int len m.length(); os.write(len); for (int i 0; i len; i) { os.write(m.charAt(i)); } os.flush(); int len1 in.read();// 等待 阻塞 System.out.println(收到消息); for (int i 0; i len1; i) { int m1 in.read(); System.out.print((char) m1); } System.out.println(); } } catch (IOException e) { throw new RuntimeException(e); } } }B.javaimport java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; public class B { public static void main(String[] args) { // 套接字的服务类 // 54321 女方家门牌号 ServerSocket ss null;// 红娘 try { ss new ServerSocket(54321); } catch (IOException e) { throw new RuntimeException(e); } try { System.out.println(等待A来连接...); Socket s ss.accept(); System.out.println(连接成功~); // 对话 InputStream in s.getInputStream();// 输入流 读取对方的消息 OutputStream os s.getOutputStream();// 输出流 给对方发消息 Scanner scanner new Scanner(System.in); while (true) { int len in.read(); System.out.println(收到消息); for (int i 0; i len; i) { int m1 in.read();// 接受消息 System.out.print((char) m1);// 转成字符打印 } System.out.println(); System.out.println(请输入消息); String m scanner.nextLine(); int len1 m.length(); os.write(len1); for (int i 0; i len1; i) { os.write(m.charAt(i));// 写字到输入框中 } os.flush();// 点击发送按钮 } } catch (IOException e) { throw new RuntimeException(e); } } }

相关新闻

5分钟解锁网易云音乐:ncmdump完整免费转换方案终极指南

5分钟解锁网易云音乐:ncmdump完整免费转换方案终极指南

5分钟解锁网易云音乐:ncmdump完整免费转换方案终极指南 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 你是否遇到过这样的困扰?从网易云音乐下载的歌曲只能在特定平台播放,无法在车载音响、手机自…

2026/7/30 9:53:36阅读更多 →
嵌入式开发串口打印调试:从printf到DMA环形缓冲区的实战指南

嵌入式开发串口打印调试:从printf到DMA环形缓冲区的实战指南

1. 串口打印:嵌入式开发的“听诊器” 在嵌入式开发的世界里,调试手段往往决定了解决问题的效率。当你的代码在目标板上跑飞,或者某个传感器的数据死活不对时,一个可靠的调试信息输出通道,就像是给系统装上了“听诊器”…

2026/7/30 9:51:35阅读更多 →
NX二次开发实战:高效实现装配体相同件判断的混合策略与算法

NX二次开发实战:高效实现装配体相同件判断的混合策略与算法

1. 项目缘起:为什么“相同件判断”是NX二次开发的硬骨头? 在制造业,尤其是非标设备、模具、汽车零部件等领域,一个装配体里存在大量外形、尺寸、属性完全相同的零件,我们习惯称之为“相同件”或“标准件”。听起来很简…

2026/7/30 9:51:35阅读更多 →
三步构建你的AI投资分析系统:TradingAgents-CN中文增强版终极指南

三步构建你的AI投资分析系统:TradingAgents-CN中文增强版终极指南

三步构建你的AI投资分析系统:TradingAgents-CN中文增强版终极指南 【免费下载链接】TradingAgents-CN 基于多智能体LLM的中文金融交易框架 - TradingAgents中文增强版 项目地址: https://gitcode.com/GitHub_Trending/tr/TradingAgents-CN 还在为复杂的股票分…

2026/7/30 15:03:10阅读更多 →
阿尔忒弥斯计划与太空经济产业链投资分析

阿尔忒弥斯计划与太空经济产业链投资分析

1. 阿尔忒弥斯计划与太空经济新纪元 2022年11月16日,NASA的SLS重型火箭搭载猎户座飞船升空,标志着阿尔忒弥斯1号任务圆满完成。当全世界还在回味月球"自拍照"时,华尔街的分析师们已经将目光投向了2024年的阿尔忒弥斯2号——这个首次…

2026/7/30 15:03:10阅读更多 →
Resemble Enhance:AI语音增强工具终极指南,5分钟实现专业级音频修复

Resemble Enhance:AI语音增强工具终极指南,5分钟实现专业级音频修复

Resemble Enhance:AI语音增强工具终极指南,5分钟实现专业级音频修复 【免费下载链接】resemble-enhance AI powered speech denoising and enhancement 项目地址: https://gitcode.com/gh_mirrors/re/resemble-enhance Resemble Enhance 是一款基…

2026/7/30 15:03:10阅读更多 →
Python模块热加载原理与实战:提升开发效率的四种实现方案

Python模块热加载原理与实战:提升开发效率的四种实现方案

1. 项目概述:为什么我们需要模块热加载?想象一下这个场景:你正在开发一个Web后端服务,或者一个需要长时间运行的数据处理脚本。每次修改了一行代码,为了验证效果,你都需要手动停止整个程序,然后…

2026/7/30 15:03:10阅读更多 →
从OJ题到工业级实现:C++动态堆栈设计与括号匹配实战

从OJ题到工业级实现:C++动态堆栈设计与括号匹配实战

1. 从一道OJ题看动态堆栈的实战价值最近在帮学弟学妹们看西北农林科技大学2024学年C面向对象程序设计的一道OJ题,题目是“T7 动态堆栈类及括号匹配”。这道题乍一看,像是数据结构课上一个经典的、甚至有点“老套”的练习题。但当我真正动手去实现&#x…

2026/7/30 15:03:10阅读更多 →
5分钟快速上手:wvp-GB28181-pro国标视频平台完整部署指南

5分钟快速上手:wvp-GB28181-pro国标视频平台完整部署指南

5分钟快速上手:wvp-GB28181-pro国标视频平台完整部署指南 【免费下载链接】wvp-GB28181-pro 基于GB28181-2016、部标808、部标1078标准实现的开箱即用的网络视频平台。自带管理页面,支持NAT穿透,支持海康、大华、宇视等品牌的IPC、NVR接入。支…

2026/7/30 15:01:10阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/30 15:03:16阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/30 12:22:27阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/29 7:58:51阅读更多 →
3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 [特殊字符]

3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 [特殊字符]

3分钟解锁iOS应用自由:TrollInstallerX让你的iPhone摆脱安装限制 🚀 【免费下载链接】TrollInstallerX A TrollStore installer for iOS 14.0 - 16.6.1 项目地址: https://gitcode.com/gh_mirrors/tr/TrollInstallerX 你是否曾经因为iOS系统的严格…

2026/7/30 0:00:58阅读更多 →
[GESP202606 四级] 扫雷

[GESP202606 四级] 扫雷

B4557 [GESP202606 四级] 扫雷 https://www.luogu.com.cn/problem/B4557 中国计算机学会(CCF)2026年6月C四级讲解——扫雷 https://www.bilibili.com/video/BV1MCMg6AEXR/ B4557 [GESP202606 四级] 扫雷 https://www.bilibili.com/video/BV1ZKTj6ZEVh/ 2…

2026/7/30 0:00:58阅读更多 →
Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南

Windows驱动存储终极清理工具:DriverStoreExplorer完全指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 您是否曾因Windows系统盘空间不足而烦恼?是否遇到过设…

2026/7/30 0:00:58阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/30 0:27:26阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/30 4:47:18阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/29 14:26:42阅读更多 →