【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

HarmonyOS6半年磨一剑 - RcImage组件核心架构与状态管理机制

HarmonyOS6半年磨一剑 - RcImage组件核心架构与状态管理机制

文章目录 * 前言 * 项目简介 * 核心特性 * 开源计划 * rchoui官网 * 第一章: 组件架构设计 * 1.1 ComponentV2 装饰器体系 * 1.2 参数系统分层设计 * 1.3 类型系统设计 * 第二章: 状态管理机制 * 2.1 加载状态机设计 * 2.2 状态转换逻辑实现 * 2.3 预览状态管理 * 第三章: 生命周期管理 * 3.1 组件生命周期钩子 * 3.2 状态更新触发机制 * 第四章: 事件系统设计 * 4.1 事件分类与职责 * 4.2 事件触发时机与顺序 * 4.3 事件参数设计 * 第五章: 渲染优化策略

By Ne0inhk
SQL Server 2025数据库安装图文教程(附SQL Server2025数据库下载安装包)

SQL Server 2025数据库安装图文教程(附SQL Server2025数据库下载安装包)

SQL Server是由微软推出的关系型数据库管理系统,它提供了可靠的数据存储、数据管理和数据分析功能。SQL Server支持多种数据处理功能,包括事务处理、数据分析、报表生成和数据挖掘等,因此在企业和组织中得到广泛应用。 演示系统:Windows server 2025数据中心版 安装包:下载传送门 1、下载并解压安装包,找到解压的安装包,双击【setup.exe】 2、双击【setup.exe】就会打开SQL Server安装中心,点击【安装】-【全新安装或向现有安装添加功能】 3、选择对应版本后,下一步 4、勾选“我接受许可条款”后下一步 5、下一步下一步 6、不勾选,下一步 7、勾选需要的功能,路径建议默认,下一步 8、下一步

By Ne0inhk
你真的会打印日志吗?基于 Spring Boot 的全方位日志指南

你真的会打印日志吗?基于 Spring Boot 的全方位日志指南

—JavaEE专栏— 目录 * 一、日志概述:为什么它比 System.out.println 更重要? * 1.1 日志的核心用途 * 1.2 为什么弃用标准输出? * 二、日志框架体系:门面模式的深度解析 * 2.1 门面模式 (Facade Pattern) * 2.2 常见框架对比 * 三、实战:Spring Boot 日志的基本使用 * 3.1 传统方式获取日志对象 * 3.2 进阶方式:使用 Lombok (@Slf4j) * 四、深入理解日志级别 * 五、日志的高级配置 (application.yml) * 5.1 修改日志级别 * 5.

By Ne0inhk
Spring Security 从入门到实战:搞定认证授权,再也不用手写权限逻辑

Spring Security 从入门到实战:搞定认证授权,再也不用手写权限逻辑

✨道路是曲折的,前途是光明的! 📝 专注C/C++、Linux编程与人工智能领域,分享学习笔记! 🌟 感谢各位小伙伴的长期陪伴与支持,欢迎文末添加好友一起交流! * 目录 * 前言 * 一、Spring Security 是什么? * 1.1 核心功能 * 二、技术组成分布 * 三、认证流程解析 * 3.1 请求处理流程 * 3.2 过滤器链结构 * 四、快速开始 * 4.1 添加依赖 * 4.2 基础配置 * 五、认证机制详解 * 5.1 内存认证(开发测试) * 5.2 数据库认证(生产推荐) * 六、授权控制方式 * 6.1 注解方式

By Ne0inhk