【Java】TCP网络编程:从可靠传输到Socket实战

【Java】TCP网络编程:从可靠传输到Socket实战

活动发起人@小虚竹 想对你说:

这是一个以写作博客为目的的创作活动,旨在鼓励大学生博主们挖掘自己的创作潜能,展现自己的写作才华。如果你是一位热爱写作的、想要展现自己创作才华的小伙伴,那么,快来参加吧!我们一起发掘写作的魅力,书写出属于我们的故事。我们诚挚邀请你参加为期14天的创作挑战赛!

提醒:在发布作品前,请将不需要的内容删除。

 各位看官,大家早安午安晚安呀~~~

如果您觉得这篇文章对您有帮助的话

欢迎您一键三连,小编尽全力做到更好
欢迎您分享给更多人哦


今天我们来学习【Java】TCP网络编程:从可靠传输到Socket实战

目录

1.首先我们再说一下TCP和UDP的区别和相同点

2.连接:通信双方都会记录对方的信息

3.主要是两个api ServerSocket和Socket

4.TCP服务端实战代码演示

5.TCP客户端实战代码演示


TCP的socket的api的差异很大,但是和前面的IO有很大的关联

1.首先我们再说一下TCP和UDP的区别和相同点

1.TCP是有连接的,UDP无连接(这一点可以在代码中体现)

2.TCP是面向字节流流的,UDP是面向数据报的

3.TCP是可靠传输的,UDP是不可靠传输的(这一点在代码中体现不出来)

4.TCP和UDP都是全双工的

2.连接:通信双方都会记录对方的信息

UDP:每次发送数据报都要指定对方的地址(UDP没有存储这个信息)

一张图



TCP:不需要(不过需要内核自动和客户端建连接(TCP的三次握手,后面我会进行讲解)这个过程是系统内核自动完成的)

对于应用程序来说,客户端是发起“建立连接”



服务器这边:把内核中建立好的连接拿到应用程序里面()

这个ServerSocket只负责绑定端口号,然后通过accept方法 把建立好的连接拿过来(但是一瞬间有很多连接的话,就像生产者消费者模型里面只能进行阻塞等待)

3.主要是两个api ServerSocket和Socket

ServerSocket是给服务器用的类,使用这个类用来绑定端口号(这个类负责把系统内核里面已经建立好的连接从队列里面拿过来,)

Socket:既会给服务器使用的类,也会给客户端使用,通过socket这个对象和客户端进行交互

(这两个类都是用来表示socket文件的,抽象了网卡这样的硬件设备)

4.TCP服务端实战代码演示

import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Scanner; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class TcpEchoServer { // 读取用Scanner ,发送用PrintWriter // 1.首先serverSocket调用系统API把连接拿过来,然后交给socket // 我们就有了socket这个对象,这个时候我们就可以宣布这个客户端成功和我们服务器建立了联系并且我们拿到了 // 2.然后我们通过字节流把数据从socket抽象的文件里面读取到,用try包起来,用scanner从流里面读取 // 3. 我们拿到字符串进行响应 // 4. 把返回的字符串通过字节流(我们的字符串通过字符流转换成字节流)写回去 // 5. 把信息打印出来 private ServerSocket serverSocket = null; public TcpEchoServer(int serverPort) throws IOException { // 利用这个系统API从内核中取到已经建立好的连接 // 这个和客户端构造的socket完全不一样,客户端的那个是我们已经拿到的连接 serverSocket = new ServerSocket(serverPort); // 服务器自己分配端口号, } public void start() throws IOException { System.out.println("服务器启动"); // 把队列里面建立好的连接拿过来 while(true){ // 要一直不断地从那个内核里面不断地拿我们已经建立好的连接!!! Socket Clientsocket = serverSocket.accept(); /* //创建一个新的线程把这个请求进行响应 Thread t = new Thread(() ->{ possessCollection(Clientsocket); }); t.start();*/ // 但是线程池是更好一点点的选择 ExecutorService service = Executors.newCachedThreadPool(); service.submit(() ->{ possessCollection(Clientsocket); }); } } public void possessCollection(Socket Clientsocket){ // System.out.printf("[%s,%d] 客户端上线\n" , Clientsocket.getInetAddress(),Clientsocket.getPort()); // 把端口号和IP拿到 try( InputStream inputStream = Clientsocket.getInputStream(); // 这里要用 " ; " OutputStream outputStream = Clientsocket.getOutputStream()){ // 客户可能等会还会继续发送请求(我们循环处理) Scanner scanner = new Scanner(inputStream);//每一次读一次缓冲区,缓冲区里面的东西就少一次,都被我读出来了嘛 while(true){ if(!scanner.hasNext()){// 用户不再输入的时候,就直接跳出循环!!!,一直等待用户输入 System.out.printf("[%s,%d] 客户端下线\n" , Clientsocket.getInetAddress(),Clientsocket.getPort()); break; } String request = scanner.next(); // 拿到字符串进行响应 String response = process(request);// 拿到响应 //4. 拿到字符串的响应,然后我们通过字符流转字节流传递出去 PrintWriter printWriter = new PrintWriter(outputStream); printWriter.println(response); // 此处的println不是写到控制台了,而是写到outputStream的流对象了,也就是写入到ClientSocket里面了 // 自然这个数据也是通过网卡发出去了 printWriter.flush();// 再刷新一下缓存,防止没有发出去, // 总结: 发送和接收数据都是通过socket文件的字节流输入输出来实现,用scanner读字节流,用printWriter写字符串 // 5.打印一下交互过程 System.out.printf("[%s,%d] req=%s resp=%s\n",Clientsocket.getInetAddress(),Clientsocket.getPort(), request,response); } }catch(IOException e){ e.printStackTrace(); }finally{ try { Clientsocket.close(); } catch (IOException e) { throw new RuntimeException(e); } } } private String process(String request) { // 回显服务器 return request; } public static void main(String[] args) throws IOException { TcpEchoServer tcpEchoServer = new TcpEchoServer(9090); tcpEchoServer.start(); } } 

但是这里面会出现两个问题

问题一:为什么我们的ServerSocket对象没有进行close操作,但是Socket对象却需要close操作呢?这样不会出现文件资源泄露吗?

首先我们需要知道什么时候回造成文件资源泄露?

直频繁申请但是一直不释放就会(什么文件的表项啥的)

但是ServerSocket对象从头到尾只创建过一次对象,而且一直在把内核中建立的连接拿到。所以说ServerSocket这个对象的生命周期是是伴随着进程消失的(因此不需要特地的进行回收,等到进程解释JVM会把这个进程里面的东西一起回收了)


但是?

问题二:等待我们写完客户端的代码之后进行讲述

如果启动多个客户端和服务器进行连接(就不行了,这个服务器一直在等待客户端进行输入,我们就需要多个线程并发拿到这个连接)

但是频繁地创建和销毁线程也会有很大开销,线程池是更好一点点选择

5.TCP客户端实战代码演示

import com.sun.xml.internal.ws.policy.privateutil.PolicyUtils; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner; public class TcpEchoClient { /** * 1.随机分配一个端口的发出信息(我们要把服务器的IP地址和端口号给搞进去) * 2.我们循环输入一个字符串,把这个字符串用字符流转换成字节流写到socket抽象的文件里面 * 3.然后我们接收响应(不像服务器,我们又不需要进行处理) * 4.我们直接通过Scanner把字节流里面的内容读出来就好了 */ private Socket socket = null; public TcpEchoClient(String serverIP,int serverPort) throws IOException { socket = new Socket(serverIP,serverPort); } public void start(){ System.out.println(" -> "); Scanner scanner = new Scanner(System.in); try(OutputStream outputStream = socket.getOutputStream(); InputStream inputStream = socket.getInputStream()){ while(true){ /* if(!scanner.hasNext()){ // 用户不想输入了,就直接退出了 break; 不需要这个 }*/ // * 2.我们循环输入一个字符串,把这个字符串用字符流转换成字节流写到socket抽象的文件里面 String request = scanner.next(); PrintWriter printWriter = new PrintWriter(outputStream); // 这些流尽量都放到try()里面 printWriter.println(request); printWriter.flush();// 一定不要忘记刷新缓存区' // * 4.我们直接通过Scanner把字节流里面的内容读出来就好了 Scanner scannerNetwork = new Scanner(inputStream); // 这个Scanner尽量也是放到try()里面 String response = scannerNetwork.next(); System.out.println(response); } }catch(IOException e){ e.printStackTrace(); } } public static void main(String[] args) throws IOException { TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1",9090); tcpEchoClient.start(); } } 
上述就是【Java】TCp网络编程:TCP网络编程:从可靠传输到Socket实战的全部内容啦

能看到这里相信您一定对小编的文章有了一定的认可。

有什么问题欢迎各位大佬指出
欢迎各位大佬评论区留言修正~~


您的支持就是我最大的动力​​​!!!

Read more

别再做学生管理系统了!这 30 个 Python 毕设题目,才是 2026 年的顶流!

别再做学生管理系统了!这 30 个 Python 毕设题目,才是 2026 年的顶流!

🧑‍💻博主介绍 & 诚邀关注 作者:专注于 Java、Python、前端开发的技术博主 | 全网粉丝 30 万 + 在校期间协助导师完成毕业设计课题分类、论文格式初审及代码整理工作;工作后持续分享毕设思路,助力毕业生顺利完成课题。 == 🔥 欢迎订阅我的专栏,获取完整源码、论文框架和部署文档,一起学习,共同进步! == * ✅ 覆盖Java/Python/LLM/单片机等全方向 * ✅ 每个项目含完整源码、论文框架、部署文档 * ✅ 持续更新,助力大家顺利完成毕设 📌精品项目推荐 1. ✅ 题目1:基于 Python + 通义千问API 的多模态数据清洗自动化系统 * 支持文本/图片/表格多类型数据导入 * 大模型自动识别脏数据+语义级清洗 * 生成交互式清洗报告,支持自定义清洗规则 * 数据存储采用国产化达梦DM8,适配政企数据分析场景 2. ✅ 题目2:基于 Python + YOLOv9

By Ne0inhk

ComfyUI v0.11.1正式发布:新增开发者专属节点支持、API节点强化、Python 3.14兼容性更新等全方位优化!

2026年1月29日,ComfyUI迎来了全新的 v0.11.1版本。本次更新属于不可变版本(immutable release),主要优化了开发者体验、API节点扩展以及稳定性。以下为本次更新的详细技术解读。 🔧版本更新概览 更新内容摘要: * 新增开发模式专用节点支持(Dev-Only Nodes) * 更新Python 3.14兼容性说明 * 新增API节点:Grok Imagine节点 * 升级管理器版本至 4.1b1 * 工作流模板更新至 v0.8.27 * 补充缺失的空间下采样比率(spacial downscale ratios) 🧩主要技术更新详情 1. 新增开发模式专用节点支持(Dev-Only Nodes) 在 comfy/comfy_types/node_typing.py 文件中新增: DEV_ONLY:bool"

By Ne0inhk

小白零基础教程:安装 Conda + VSCode 配置 Python 开发环境

小白零基础教程:安装 Conda + VSCode 配置 Python 开发环境 前言 本教程专为电脑小白设计,全程无复杂术语,步骤详细到每一步点击,覆盖 Windows 10/11、macOS 系统(Linux 可参考 macOS 终端操作)。核心目标:安装轻量版 Conda(Miniconda)→ 配置 Conda 环境 → VSCode 关联 Conda 运行 Python,解决「环境冲突」「命令找不到」「解释器选不到」等常见问题。 一、准备工作 1. 操作系统:Windows 10/11(64 位)或 macOS(Intel/

By Ne0inhk

Python 代码打包为 exe 全攻略:6 种主流方法原理 + 步骤 + 避坑指南

Python 代码打包为 exe 全攻略(2025–2026 主流方案) 目前 Python 程序打包成 Windows 可执行文件(.exe)的方案已经非常成熟,主要有以下 6 种主流/常用的方式: 排名工具名称是否打包解释器文件体积启动速度兼容性维护活跃度推荐场景难度1PyInstaller是中~大较慢★★★★★非常活跃几乎所有场景首选★★☆2Nuitka编译为 C → exe中~小很快★★★★☆活跃追求速度 & 体积小的项目★★★3PyOxidizerRust 打包中~小很快★★★★活跃追求极致启动速度 & 现代化★★★★4cx_Freeze是中较慢★★★★一般简单脚本、跨平台需求★★☆5py2exe是中~大较慢★★★较少维护极老项目兼容(Python 3 支持一般)★★☆6Shiv / PEX不打包,zipapp非常小快★★★★活跃命令行工具、分发给有 Python

By Ne0inhk