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

[网络编程]通过java用TCP实现网络编程

文章目录

  • 一. 通过java用TCP实现网络编程
    • api介绍
    • 代码实现
    • 上述代码存在的问题

一. 通过java用TCP实现网络编程

api介绍

1. ServerSocket
ServerSocket是专门给服务器用的api
构造方法:
在这里插入图片描述
方法:
在这里插入图片描述
2. Socket
不管是客⼾端还是服务端Socket,都是双⽅建⽴连接以后,保存的对端信息,及⽤来与对⽅收发数据

构造方法:
在这里插入图片描述
方法:
在这里插入图片描述

代码实现

服务器:
第一步: 创建对象
在这里插入图片描述

第二步: 实现start
2.1 首先要建立连接
在这里插入图片描述
这个ServerSocket的作用, 其实就是为了连接, 连接完成之后, 返回的是Socket对象, 接下来服务器进行的工作都是Socket完成的
调用start方法后, 如果没有客户端发送请求, 那么就是在accept这里阻塞等待

单独整理一个方法处理连接后的逻辑, 需要循环处理客户端的请求

第三步: 实现processConnection方法

3.1 打印一个日志, 告知服务器当前有客户端连上了
在这里插入图片描述
3.2 从socket获取流对象, 来进一步进行后续操作
在这里插入图片描述
因为TCP是字节流传输, 所以可以使用InputStream, OutputStream来接收客户端的数据, 从而进行读写操作
3.3 读取请求并解析
在这里插入图片描述

  1. 为什么不适用read , 而是使用scanner
    使用read返回的是字节数组, 那么为了后续方便打印, 还需要将字节数组转成String
    而InputStream本身就可以搭配Scanner使用, 此时scanner.next返回的直接是String
  2. if条件判断的含义
    如果客户端终止了, 那么scanner.hasNext返回的就是false, 取反就是true, 此时就表示客户端已经断开连接了, 就可以直接break, 无需执行后面的逻辑了
    如果客户端没有终止, 但是没有发送数据过来, 此时hasNext是阻塞的
    如果发送了数据过来, 那么hasNext返回true, 取反false, 不会进入if中, 就会继续执行后面的逻辑
  3. 但是使用scanner有个弊端, scanner.next这个读取方式, 只有读到"空白符"才会读取完毕, 不然就会一直阻塞, 直到有"空白符"请求为止, 所以就要求客户端在发送数据的时候, 务必要在每个请求的末尾加上空白符

空白符是一类字符的通称, 包括 换行, 回车, 空格, 制表符, 翻页符…

3.4 根据请求计算响应
在这里插入图片描述在这里插入图片描述
由于是回显程序, 直接返回即可
但是要明确给数据加上一个"空白符", 防止阻塞

3.5 把响应写回给客户端
在这里插入图片描述
3.6 打印日志
在这里插入图片描述

第四步: 实现main方法
在这里插入图片描述

完整代码:

public class TcpEchoServer {private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {while(true){Socket clientSocket = serverSocket.accept();processConnection(clientSocket);}}private void processConnection(Socket clientSocket) throws IOException {//1. 打印一个日志, 告知说当前有客户端连上了System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());//2. 从socket获取流对象, 来进一步进行后续操作try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()){//3. 读取请求并响应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();//4. 根据请求计算响应String response = process(request);//5. 把响应写回到客户端outputStream.write(response.getBytes(), 0, response.getBytes().length);//6. 服务器打印日志System.out.printf("[%s:%d] res=%s, resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(),request,response);}}}private String process(String request) {return request + "\n";}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
}

客户端:

第一步: 创建对象
在这里插入图片描述
这样的构造方式, 就完成了和服务器之间的连接

第二步: 完成start
2.1 准备工作
在这里插入图片描述
打印日志
从socket获取字节流对象, 为后续接收发送数据做准备
用scannerNetwork来接收服务器返回的结果, 不用再进行转字符操作

2.2从控制台读取数据
在这里插入图片描述
2.3 把请求发送给服务器
在这里插入图片描述
因为服务器那边只有接收到"\n"才会停止读取, 所以我们手动加上
使用outputStream.write来发送数据

2.4 从服务器读取响应
在这里插入图片描述
如果服务器断开或者没有连接上服务器, scannerNetwork返回false, 取反true, 就会break
如果连接上了服务器, 就会返回, 用response接收

2.5 把响应显示到控制台上
在这里插入图片描述

第三步: 完成main方法
在这里插入图片描述
完整代码:

public class TcpEchoClient {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(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){Scanner scannerNetwork = new Scanner(inputStream);while(true){//1. 从控制台读取数据System.out.println("请输入要发送的数据:");String request = scanner.next();//2. 把请求发送给服务器request += "\n";outputStream.write(request.getBytes());//3. 从服务器读取响应if(!scannerNetwork.hasNext()){break;}String response = scannerNetwork.next();//4. 把响应显示到控制台上System.out.println(response);}}catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);client.start();}}

运行结果:
在这里插入图片描述
在这里插入图片描述

上述代码存在的问题

1. 服务器中, 对于accept创建的socket对象, 没有进行关闭操作
服务器serverSocket是不必关闭的, 因为他的声明周期是跟随整个服务器进程的, 他要一直等待连接
客户端的socket, 也是不必关闭的, 它跟随客户端的生命周期, 客户端结束它才要结束在这里插入图片描述

但是服务器的clientSocket就不可以不关闭了, 因为每个客户端都有对应的clientSocket, 如果用完了不关闭, 就会使当前的clientSocket对应的文件描述附表得不到释放, 引进文件资源泄露

解决办法:
我们可以在processConnection中加入finally或者将clientSocket方法try()中
在这里插入图片描述
在这里插入图片描述
**2. 当前这个代码, 服务器是无法同时给多个客户端提供服务的
在这里插入图片描述
启动多个客户端, 服务器是感知不到的, 只能当上一个客户端终止, 下一个客户端才能连接上
原因:
在这里插入图片描述
我们这个代码, 当一个客户端正在连接时, 此时进入到processConnection方法中, 进行while循环, 如果第二个客户端来了, 是没法执行到accept的
解决办法:
可以使用多线程, 让连接客户端和处理客户端的响应可以一起进行
在这里插入图片描述
注意: 此时就只能在processConnection中close掉clientSocket

服务器完整代码:

public class TcpEchoServer {private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {while(true){Socket clientSocket = serverSocket.accept();Thread thread = new Thread(() -> {try {processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}});thread.start();}}private void processConnection(Socket clientSocket) throws IOException {//1. 打印一个日志, 告知说当前有客户端连上了System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());//2. 从socket获取流对象, 来进一步进行后续操作try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()){//3. 读取请求并响应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();//4. 根据请求计算响应String response = process(request);//5. 把响应写回到客户端outputStream.write(response.getBytes(), 0, response.getBytes().length);//6. 服务器打印日志System.out.printf("[%s:%d] res=%s, resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(),request,response);}}finally{clientSocket.close();}}private String process(String request) {return request + "\n";}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
}

相关文章:

[网络编程]通过java用TCP实现网络编程

文章目录 一. 通过java用TCP实现网络编程api介绍代码实现上述代码存在的问题 一. 通过java用TCP实现网络编程 api介绍 1. ServerSocket ServerSocket是专门给服务器用的api 构造方法: 方法: 2. Socket 不管是客⼾端还是服务端Socket,都是双⽅建⽴连接以后&#…...

Python(TensorFlow)和Java及C++受激发射损耗导图

🎯要点 神经网络监督去噪预测算法聚焦荧光团和检测模拟平台伪影消除算法性能优化方法自动化多尺度囊泡动力学成像生物研究多维分析统计物距粒子概率算法 Python和MATLAB图像降噪算法 消除噪声的一种方法是将原始图像与表示低通滤波器或平滑操作的掩模进行卷积。…...

IEEE投稿模板翻译

>将这一行替换为您的稿件id号(双击此处编辑)< IEEE 期刊和会议论文的撰写准备&#xff08;2022&#xff09; 第一作者 A. 作者&#xff0c;IEEE成员&#xff0c;第二作者 B. 作者&#xff0c;第三作者 C. 作者 Jr.&#xff0c;IEEE成员 摘要—本文档为IEEE会刊、期刊和…...

log4j 1.x 日志输出线程以唯一ID的形式配置

在 Log4j 1.x 中&#xff0c;直接以线程ID&#xff08;如Java中的Thread.currentThread().getId()返回的ID&#xff09;的形式记录日志是可行的&#xff0c;但 Log4j 1.x 本身并不直接提供一个内建的、自动将每个线程ID转换为“同一时间段内唯一ID”的机制。线程ID本身在JVM的上…...

宏观学习笔记:GDP分析(二)

GDP分析&#xff08;一&#xff09;主要是介绍GDP相关的定义以及核算逻辑&#xff0c;本节主要介绍GDP的分析思路。GDP分析主要是2种方法&#xff1a;总量分析和结构分析。 1. 总量分析 1.1 数值选择 一般情况下&#xff0c;分析的对象都是 官方公布的GDP当季值。 1.2 趋势规…...

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位&#xff1a;为1时表示在内存期间被访问过&#xff0c;为0时表示未被访问&#xff1b;修改位&#xff1a;为1时表示该页面自从被装入内存后被修改过&#xff0c;为0时表示未修改过。 置换页面时&#xff0c;最先置换访问位和修改位为…...

C高级编程 第十六天(树 二叉树)

1.树 1.1结构特点 非线性结构&#xff0c;有一个直接前驱&#xff0c;但可能有多个直接后继有递归性&#xff0c;树中还有树可以为空&#xff0c;即节点个数为零 1.2相关术语 根&#xff1a;即根结点&#xff0c;没有前驱叶子&#xff1a;即终端结点&#xff0c;没有后继森…...

OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆&#xff0c;该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使…...

904.水果成篮

题目 链接&#xff1a;leetcode链接 思路分析&#xff08;滑动窗口&#xff09; 读完题目&#xff0c;很明显&#xff0c;这个题目需要我们寻找一个最长子数组&#xff0c;使得这个子数组里面最多存在两种不同的数字&#xff0c;很容易联想到使用滑动窗口。 另外&#xff…...

【网络安全】漏洞挖掘之 2FA 恢复代码安全措施不当

未经许可,不得转载。 文章目录 正文正文 目标:example.com 2024年6月,我在HackerOne上参与一个私人项目时发现了一个与2FA(双因素身份验证)恢复代码管理相关的安全漏洞。该漏洞发生在用户禁用并重新启用2FA的过程中。问题在于,系统在2FA重新启用后,仍然接受此前生成的…...

指令微调与参数微调的代码实践与分析

文章目录 指令微调的实验性分析LoRA 代码实践与分析指令微调的示例代码与预训练的代码高度一致,区别主要在于指令微调数据集的构建(SFTDataset)和序列到序列损失的计算(DataCollatorForSupervisedDataset)。以下代码展示了 LLMBox 和 YuLan-Chat 中指令微调的整体训练流程…...

Android14音频进阶之高通Elite架构指定通道播放(八十四)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…...

常见的正则化方法以及L1,L2正则化的简单描述

深度学习中的正则化是通过在模型训练过程中引入某些技术来防止模型过拟合的一种策略。过拟合是指模型在训练数据上表现非常好&#xff0c;但在新的、未见过的数据上表现不佳。正则化通过限制模型的复杂度或对模型参数施加约束&#xff0c;从而提高模型的泛化能力。 常见的正则…...

深入理解 Milvus:新一代向量数据库的基础技术与实战指南

一、什么是 Milvus&#xff1f; Milvus 是一个开源的向量数据库&#xff0c;专门设计用于存储和检索大规模的高维向量数据。无论是图像、视频、音频还是文本&#xff0c;通过将这些数据转换为向量&#xff0c;Milvus 都能通过近似最近邻搜索&#xff08;Approximate Nearest N…...

Maven教程——从入门到入坑

第1章 为什么要使用Maven 1.1 获取第三方jar包   开发中需要使用到的jar包种类繁多&#xff0c;获取jar包的方式都不尽相同。为了查找一个jar包找遍互联网&#xff0c;身心俱疲。不仅如此&#xff0c;费劲心血找到的jar包里有的时候并没有你需要的那个类&#xff0c;又或者有…...

研究生深度学习入门的十天学习计划------第九天

第9天&#xff1a;深度学习中的迁移学习与模型微调 目标&#xff1a; 理解迁移学习的核心概念&#xff0c;学习如何在实际应用中对预训练模型进行迁移和微调&#xff0c;以应对不同领域的任务。 9.1 什么是迁移学习&#xff1f; 迁移学习&#xff08;Transfer Learning&#…...

perl的学习记录——仿真regression

1 记录的背景 之前只知道有这个强大语言的存在&#xff0c;但一直侥幸自己应该不会用到它&#xff0c;所以一直没有开始学习。然而人生这么长&#xff0c;怎就确定自己不会用到呢&#xff1f; 这次要搭建一个可以自动跑完所有case并且打印每个case的pass信息到指定的文件中。…...

【Go】go连接clickhouse使用TCP协议

离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么 &#x1f3b5; 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time&q…...

Emlog-Pro访问网站时需要密码验证插件

插件介绍 EmlogPro访问网站密码验证插件&#xff0c;为你的网站添加输入密码访问网站功能&#xff0c;在应用中的场景往往运用在为内部或是个人使用的页面里面&#xff0c;在访问的时候可以提示输入密码&#xff0c;做隐私保护。 下载地址&#xff1a; Emlog-Pro访问网站时需…...

Apache ShardingSphere数据分片弹性伸缩加解密中间件

Apache ShardingSphere Apache ShardingSphere 是一款分布式 SQL 事务和查询引擎,可通过数据分片、弹性伸缩、加密等能力对任意数据库进行增强。 软件背景 ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding…...

RestClient

什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端&#xff0c;它允许HTTP与Elasticsearch 集群通信&#xff0c;而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级&#xff…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

css实现圆环展示百分比,根据值动态展示所占比例

代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...

安宝特方案丨XRSOP人员作业标准化管理平台:AR智慧点检验收套件

在选煤厂、化工厂、钢铁厂等过程生产型企业&#xff0c;其生产设备的运行效率和非计划停机对工业制造效益有较大影响。 随着企业自动化和智能化建设的推进&#xff0c;需提前预防假检、错检、漏检&#xff0c;推动智慧生产运维系统数据的流动和现场赋能应用。同时&#xff0c;…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

从零开始打造 OpenSTLinux 6.6 Yocto 系统(基于STM32CubeMX)(九)

设备树移植 和uboot设备树修改的内容同步到kernel将设备树stm32mp157d-stm32mp157daa1-mx.dts复制到内核源码目录下 源码修改及编译 修改arch/arm/boot/dts/st/Makefile&#xff0c;新增设备树编译 stm32mp157f-ev1-m4-examples.dtb \stm32mp157d-stm32mp157daa1-mx.dtb修改…...

VTK如何让部分单位不可见

最近遇到一个需求&#xff0c;需要让一个vtkDataSet中的部分单元不可见&#xff0c;查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行&#xff0c;是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示&#xff0c;主要是最后一个参数&#xff0c;透明度…...

HarmonyOS运动开发:如何用mpchart绘制运动配速图表

##鸿蒙核心技术##运动开发##Sensor Service Kit&#xff08;传感器服务&#xff09;# 前言 在运动类应用中&#xff0c;运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据&#xff0c;如配速、距离、卡路里消耗等&#xff0c;用户可以更清晰…...