[网络编程]通过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 读取请求并解析

- 为什么不适用read , 而是使用scanner
使用read返回的是字节数组, 那么为了后续方便打印, 还需要将字节数组转成String
而InputStream本身就可以搭配Scanner使用, 此时scanner.next返回的直接是String - if条件判断的含义
如果客户端终止了, 那么scanner.hasNext返回的就是false, 取反就是true, 此时就表示客户端已经断开连接了, 就可以直接break, 无需执行后面的逻辑了
如果客户端没有终止, 但是没有发送数据过来, 此时hasNext是阻塞的
如果发送了数据过来, 那么hasNext返回true, 取反false, 不会进入if中, 就会继续执行后面的逻辑 - 但是使用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 期刊和会议论文的撰写准备(2022) 第一作者 A. 作者,IEEE成员,第二作者 B. 作者,第三作者 C. 作者 Jr.,IEEE成员 摘要—本文档为IEEE会刊、期刊和…...
log4j 1.x 日志输出线程以唯一ID的形式配置
在 Log4j 1.x 中,直接以线程ID(如Java中的Thread.currentThread().getId()返回的ID)的形式记录日志是可行的,但 Log4j 1.x 本身并不直接提供一个内建的、自动将每个线程ID转换为“同一时间段内唯一ID”的机制。线程ID本身在JVM的上…...
宏观学习笔记:GDP分析(二)
GDP分析(一)主要是介绍GDP相关的定义以及核算逻辑,本节主要介绍GDP的分析思路。GDP分析主要是2种方法:总量分析和结构分析。 1. 总量分析 1.1 数值选择 一般情况下,分析的对象都是 官方公布的GDP当季值。 1.2 趋势规…...
两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容
1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为…...
C高级编程 第十六天(树 二叉树)
1.树 1.1结构特点 非线性结构,有一个直接前驱,但可能有多个直接后继有递归性,树中还有树可以为空,即节点个数为零 1.2相关术语 根:即根结点,没有前驱叶子:即终端结点,没有后继森…...
OpenCV结构分析与形状描述符(11)椭圆拟合函数fitEllipse()的使用
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 围绕一组2D点拟合一个椭圆。 该函数计算出一个椭圆,该椭圆在最小二乘意义上最好地拟合一组2D点。它返回一个内切椭圆的旋转矩形。使…...
904.水果成篮
题目 链接:leetcode链接 思路分析(滑动窗口) 读完题目,很明显,这个题目需要我们寻找一个最长子数组,使得这个子数组里面最多存在两种不同的数字,很容易联想到使用滑动窗口。 另外ÿ…...
【网络安全】漏洞挖掘之 2FA 恢复代码安全措施不当
未经许可,不得转载。 文章目录 正文正文 目标:example.com 2024年6月,我在HackerOne上参与一个私人项目时发现了一个与2FA(双因素身份验证)恢复代码管理相关的安全漏洞。该漏洞发生在用户禁用并重新启用2FA的过程中。问题在于,系统在2FA重新启用后,仍然接受此前生成的…...
指令微调与参数微调的代码实践与分析
文章目录 指令微调的实验性分析LoRA 代码实践与分析指令微调的示例代码与预训练的代码高度一致,区别主要在于指令微调数据集的构建(SFTDataset)和序列到序列损失的计算(DataCollatorForSupervisedDataset)。以下代码展示了 LLMBox 和 YuLan-Chat 中指令微调的整体训练流程…...
Android14音频进阶之高通Elite架构指定通道播放(八十四)
简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…...
常见的正则化方法以及L1,L2正则化的简单描述
深度学习中的正则化是通过在模型训练过程中引入某些技术来防止模型过拟合的一种策略。过拟合是指模型在训练数据上表现非常好,但在新的、未见过的数据上表现不佳。正则化通过限制模型的复杂度或对模型参数施加约束,从而提高模型的泛化能力。 常见的正则…...
深入理解 Milvus:新一代向量数据库的基础技术与实战指南
一、什么是 Milvus? Milvus 是一个开源的向量数据库,专门设计用于存储和检索大规模的高维向量数据。无论是图像、视频、音频还是文本,通过将这些数据转换为向量,Milvus 都能通过近似最近邻搜索(Approximate Nearest N…...
Maven教程——从入门到入坑
第1章 为什么要使用Maven 1.1 获取第三方jar包 开发中需要使用到的jar包种类繁多,获取jar包的方式都不尽相同。为了查找一个jar包找遍互联网,身心俱疲。不仅如此,费劲心血找到的jar包里有的时候并没有你需要的那个类,又或者有…...
研究生深度学习入门的十天学习计划------第九天
第9天:深度学习中的迁移学习与模型微调 目标: 理解迁移学习的核心概念,学习如何在实际应用中对预训练模型进行迁移和微调,以应对不同领域的任务。 9.1 什么是迁移学习? 迁移学习(Transfer Learning&#…...
perl的学习记录——仿真regression
1 记录的背景 之前只知道有这个强大语言的存在,但一直侥幸自己应该不会用到它,所以一直没有开始学习。然而人生这么长,怎就确定自己不会用到呢? 这次要搭建一个可以自动跑完所有case并且打印每个case的pass信息到指定的文件中。…...
【Go】go连接clickhouse使用TCP协议
离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么 🎵 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time&q…...
Emlog-Pro访问网站时需要密码验证插件
插件介绍 EmlogPro访问网站密码验证插件,为你的网站添加输入密码访问网站功能,在应用中的场景往往运用在为内部或是个人使用的页面里面,在访问的时候可以提示输入密码,做隐私保护。 下载地址: Emlog-Pro访问网站时需…...
Apache ShardingSphere数据分片弹性伸缩加解密中间件
Apache ShardingSphere Apache ShardingSphere 是一款分布式 SQL 事务和查询引擎,可通过数据分片、弹性伸缩、加密等能力对任意数据库进行增强。 软件背景 ShardingSphere是一套开源的分布式数据库中间件解决方案组成的生态圈,它由Sharding-JDBC、Sharding-Proxy和Sharding…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
QMC5883L的驱动
简介 本篇文章的代码已经上传到了github上面,开源代码 作为一个电子罗盘模块,我们可以通过I2C从中获取偏航角yaw,相对于六轴陀螺仪的yaw,qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...
大数据零基础学习day1之环境准备和大数据初步理解
学习大数据会使用到多台Linux服务器。 一、环境准备 1、VMware 基于VMware构建Linux虚拟机 是大数据从业者或者IT从业者的必备技能之一也是成本低廉的方案 所以VMware虚拟机方案是必须要学习的。 (1)设置网关 打开VMware虚拟机,点击编辑…...
微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
