【JavaEE精炼宝库】 网络编程套接字——UDP业务逻辑 | TCP流套接字编程及业务逻辑实现
文章目录
- 一、UDP业务逻辑实现
- 二、TCP流套接字编程
- 2.1 API 介绍:
- 2.1.1 ServerSocket:
- 2.1.2 Socket:
- 2.2 Java流套接字通信模型:
- 2.3 代码示例:
- 2.3.1 TCP Echo Server:
- 2.3.2 TCP Echo Client:
- 2.3.3 TCP Echo Server优化:
- 2.4 长短连接:
- 三、TCP业务逻辑实现
一、UDP业务逻辑实现
在上一节:网络编程套接字(上)中我们已经初识了网络编程和利用UDP数据报套接字进行编程。为了更加熟练掌握网络编程,接下来我们会利用UDP套接字来实现一个查询英语单词的简单业务逻辑。
-
业务目标: 编写UDP版本的字典客户端和字典服务器:
-
业务实现逻辑: 添加业务逻辑一般都是修改服务器。因为服务器是在我们手里的,客户端不是,且请求的回响是根据服务器来完成的。因此我们只需修改服务器代码即可,客户端的代码不用修改。
-
业务实现:
通过对比我们发现,要在服务器实现一个查询英语单词的逻辑,其实只要修改将请求生成回响的过程即可。 由于我们前面编写的UDPServer是回显服务器,所以我们可以通过继承的方式,重写process
方法即可。具体代码如下:
注意:要修改成自己电脑的 IP 地址才行。
import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;
public class UdpDicServer extends UdpEchoServer{private Map<String,String> hash = new HashMap<>();public UdpDicServer(int port) throws SocketException {super(port);hash.put("hello","你好");hash.put("dog","小狗");hash.put("cat","小猫");}@Overridepublic String process(String request) {return hash.getOrDefault(request,"该词汇未被查询到");}public static void main(String[] args) throws IOException {UdpDicServer server = new UdpDicServer(9090);server.start();}
}
实现效果如下:
二、TCP流套接字编程
2.1 API 介绍:
2.1.1 ServerSocket:
ServerSocket 是创建TCP服务端Socket的API。
- ServerSocket 构造方法:
方法签名 | 方法说明 |
---|---|
ServerSocket(int port) | 创建一个服务端流套接字Socket,并绑定到指定端口。 |
- ServerSocket 普通方法:
方法签名 | 方法说明 |
---|---|
Socket accept() | 开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待。 |
void close() | 关闭此套接字。 |
2.1.2 Socket:
Socket是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服 务端Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存对端的信息,用来与对方收发数据 。
- Socket 构造方法:
方法签名 | 方法说明 |
---|---|
Socket(String host, int port) | 创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接。 |
- Socket 普通方法:
方法签名 | 方法说明 |
---|---|
InetAddress getInetAddress() | 返回套接字所连接的地址。 |
InputStream getInputStream() | 返回此套接字的输入流。 |
OutputStream getOutputStream() | 返回此套接字的输出流。 |
2.2 Java流套接字通信模型:
TCP流套接字较UDP数据报套接字就要灵活许多,通信双方建立联系后,就可以通过我们前面学过的 IO 流进行数据传输,非常方便。
2.3 代码示例:
2.3.1 TCP Echo Server:
首先创建 ServerSocket,接着通过 accept 方法接收Socket,建立连接后通过 IO 流进行数据交互。
代码如下:
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.ExecutorService;
import java.util.concurrent.Executors;public class TcpEchoServer {private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");
// 单线程while(true){Socket clientSocket = serverSocket.accept();//连接后的逻辑processConnection(clientSocket);}}/*** 处理连接后的逻辑* @param clientSocket* @throws IOException*/private void processConnection(Socket clientSocket) throws IOException {//这种写法的好处是:可以优雅的 closetry (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {Scanner in = new Scanner(inputStream);while (true) {//读取完毕if (!in.hasNext()) {System.out.printf("[%s:%d]客户端下线", clientSocket.getInetAddress(), clientSocket.getPort());break;}//获取请求String request = in.next();//根据请求计算响应String response = process(request);//将响应写回给客户端PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);//刷新缓存区printWriter.flush();//打印日志System.out.printf("[%s:%d] req:%s resp:%s\n", clientSocket.getInetAddress(), clientSocket.getPort(), request,response);}}finally{clientSocket.close();}}//根据请求计算响应public String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
}
2.3.2 TCP Echo Client:
创建 Socket 向 ServerSocket 发起连接请求,连接成功后,通过 IO 流进行数据交互。
代码如下:
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 {private Socket socket = null;public TcpEchoClient(String serverIp, int serverPort) throws IOException {socket = new Socket(serverIp, serverPort);}public void start() throws IOException {System.out.println("客户端启动!");Scanner in = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while (true) {//提示输入请求System.out.print("请输入请求:");//输入请求String request = in.next();//发送给服务器获取响应PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);//保证数据发送出去了printWriter.flush();Scanner scanner = new Scanner(inputStream);String response = scanner.next();//打印响应System.out.println(response);}}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("192.168.0.198", 9090);client.start();}
}
演示效果如下:
2.3.3 TCP Echo Server优化:
普通的 TCP Echo Server 存在服务器一次只能与一个客户端进行连接的问题,这显然不是我们想要的。
我们可以通过前面所学的多线程来解决这个问题。给每个客户端都分配一个线程。
- 多线程优化:
由于修改的只是 start 方法,下面就只给出 start 多线程版本,大家自己替换一下即可。
public void start() throws IOException {System.out.println("服务器启动!");
// 使用多线程来解决多个客户端的情况while (true) {Socket clientSocket = serverSocket.accept();Thread thread = new Thread(()->{try {//用该方法来封装一个连接的逻辑processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}});thread.start();}}
多线程的效果如下:
- 线程池优化:
采用线程池的优势有:
1. 减低资源开销: 避免频繁的创建和销毁线程带来的系统资源开销。
2. 提高响应速度: 可以直接利用线程池中存在的线程,不用等待创建线程的时间。
3. 可管理性: 进行统一的分配,可以避免大量因抢占式系统资源分配带来的阻塞。
代码如下:
public void start() throws IOException {System.out.println("服务器启动!");//线程池解决多个客户端的情况ExecutorService service = Executors.newCachedThreadPool();while(true){Socket clientSocket = serverSocket.accept();service.submit(()->{try {processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}});}}
线程池效果如下:
2.4 长短连接:
TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接:
- 短连接: 每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。
- 长连接: 不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。
对比以上长短连接,两者区别
如下:
- 建立连接、关闭连接的耗时: 短连接每次请求、响应都需要建立连接,关闭连接,而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
- 主动发送请求对象: 短连接一般是客户端主动向服务端发送请求,而长连接可以是客户端主动发送请求,也可以是服务端主动发。
- 两者的使用场景:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等。
三、TCP业务逻辑实现
-
业务目标: 编写TCP版本的字典客户端和字典服务器:
-
业务实现逻辑: 和上面的 UDP业务逻辑实现一样,这里就不再赘述。
-
业务实现:
代码如下:
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;public class TcpDirServer extends TcpEchoServer{private Map<String,String> hash = null;public TcpDirServer(int port) throws IOException {super(port);hash = new HashMap<>();hash.put("hello","你好");hash.put("cat","小猫");hash.put("dog","小狗");}@Overridepublic String process(String request) {return hash.getOrDefault(request,"该单词查询不到");}public static void main(String[] args) throws IOException {TcpDirServer server = new TcpDirServer(9090);server.start();}
}
效果如下:
结语:
其实写博客不仅仅是为了教大家,同时这也有利于我巩固知识点,和做一个学习的总结,由于作者水平有限,对文章有任何问题还请指出,非常感谢。如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。
相关文章:

【JavaEE精炼宝库】 网络编程套接字——UDP业务逻辑 | TCP流套接字编程及业务逻辑实现
文章目录 一、UDP业务逻辑实现二、TCP流套接字编程2.1 API 介绍:2.1.1 ServerSocket:2.1.2 Socket: 2.2 Java流套接字通信模型:2.3 代码示例:2.3.1 TCP Echo Server:2.3.2 TCP Echo Client:2.3.…...
前端过渡动画
前端过渡动画 vue3 1、组件进入视口时向上移动且渐显 1、创建js文件addViewportEffect.js function slideDownEffect(element) {console.log("执行");element.style.transform translateY(0);element.style.opacity 1; }/*** 添加视口效果到指定的类名元素上。…...
actual combat 38 ——vue
vue-cli脚手架 创建命令:vue create 项目名称 eslint 如何关闭? vue.config.js文件中加 module.exports {lintOnSave: false }文件全代码: const { defineConfig } require(vue/cli-service) module.exports defineConfig({transpile…...
测试面试宝典(四十七)— 功能测试用例一般包含哪些内容
首先,明确测试用例的编号和名称,以便于识别和管理。 其次,详细描述测试的目标和背景,让其他人能够清楚了解该测试用例的目的和适用场景。 接着是测试的步骤,需要清晰、准确地列出每一个操作步骤,包括输入…...
rust_mac环境安装
在 macOS 上安装 Rust 很简单。你可以使用 Rust 提供的安装工具 rustup。下面是安装步骤: 打开终端。 运行以下命令以安装 rustup 和 Rust: curl --proto https --tlsv1.2 -sSf https://sh.rustup.rs | sh按照提示进行操作: 这个命令将下载并…...

【前端面试】七、算法-递归
常考算法 排序算法:快速排序、归并排序、堆排序等。 查找算法:二分查找、哈希表查找等。 动态规划:解决最优化问题,如斐波那契数列、最长公共子序列等。 图论算法:最短路径(Dijkstra、Floyd-Warshall&am…...

CmsEasy逻辑漏洞--零元购
CmsEasy逻辑漏洞--零元购 选择购买MackBook 购买成功后会员中心发现多出8100快钱 然后就可以正常购买了...

Linux 内核源码分析---I/O 体系结构与访问设备
I/O 体系结构 与外设的通信通常称之为输入输出,一般都缩写为I/O。 在实现外设的I/O时,内核必须处理3个可能出现的问题: (1)必须根据具体的设备类型和模型,使用各种方法对硬件寻址; (…...

在cPanelWHM中如何重置 MySQL 用户帐户密码
更改MySQL用户账户密码非常简单。服务器管理员可以在WHM中编辑任何MySQL用户的帐户。cPanel用户可以编辑其帐户管理的数据库的密码。 在WHM中更改MySQL用户帐户密码 打开WHM,在侧边菜单中的SQL服务下选择“Change MySQLUser Password”。Hostease的服务器产品提供稳…...

软件测试基础1--功能测试
1、什么是软件测试? 软件是控制计算机硬件运行的工具。 软件测试:使用技术手段验证软件是否满足使用需求,为了发现软件功能和需求不相符合的地方,或者寻找实际输出和预期输出之间的差异。 软件测试的目的:减少软件缺陷…...

《计算机网络》(第8版)第9章 无线网络和移动网络 复习笔记
第 9 章 无线网络和移动网络 一、无线局域网 WLAN 1 无线局域网的组成 无线局域网提供移动接入的功能,可分为两大类:有固定基础设施的和无固定基础设 施的。 (1)IEEE 802.11 IEEE 802.11 是无线以太网的标准,是有固定…...

非负数、0和正整数 限制最大值且保留两位小数在elementpuls表单中正则验证
一、结构 <el-form-item label"单价:" prop"price"><el-inputv-model.trim"formData.price"placeholder"请输入"blur"formMethod.fixTwo"><template #append>(元)</template></el-i…...

Java多线程-----定时器(Timer)及其实现
目录 一.定时器简介: 二.定时器的构造方法与常见方法: 三.定时器的模拟实现: 思路分析: 代码实现: 在开发中,我们经常需要一些周期性的操作,例如每隔几分钟就进行某一项操作,这…...

【Linux修行路】进度条小程序
目录 ⛳️推荐 一、预备知识 1.1 回车换行 1.2 缓冲区 二、倒计时 2.1 注意事项 三、进度条 3.1 源代码 3.2 代码分析 3.2 实际使用场景 ⛳️推荐 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家…...

网络安全入门教程(非常详细)从零基础入门到精通,看完这一篇就够了。
学前感言: 1.这是一条坚持的道路,三分钟的热情可以放弃往下看了.2.多练多想,不要离开了教程什么都不会了.最好看完教程自己独立完成技术方面的开发.3.有时多google,baidu,我们往往都遇不到好心的大神,谁会无聊天天给你做解答.4.遇到实在搞不懂的,可以先放放,以后再来解决. 基…...

【探索Linux】P.44(数据链路层 —— 以太网的帧格式 | MAC地址 | MTU | ARP协议)
阅读导航 引言一、认识以太网二、以太网的帧格式三、MAC地址四、MTU五、ARP协议温馨提示 引言 在深入探讨了网络层的IP协议之后,本文将带领读者进一步深入网络的底层——数据链路层。我们将详细解析以太网的帧格式,这是数据链路层传输数据的基本单元&am…...

<数据集>航拍行人识别数据集<目标检测>
数据集格式:VOCYOLO格式 图片数量:7482张 标注数量(xml文件个数):7482 标注数量(txt文件个数):7482 标注类别数:1 标注类别名称:[people, pedestrian] 序号类别名称图片数框数1people5226385602pedes…...
在 Windows 10 系统上部署 Medusa
先决条件 在安装 Medusa 之前,你需要确保已经安装了以下工具: Node.js: Medusa 需要 Node.js v16 或更高版本。你可以从 Node.js 官网下载并安装。Git: Git 用于从 GitHub 获取 Medusa 的源代码。你可以从 Git 官网下载并安装。PostgreSQL: Medusa 使用…...

Linux进程 (冯诺依曼体结构 管理 PCB 进程状态 僵尸进程 孤儿进程 运行阻塞挂起状态 进程优先级)
文章目录 一.冯诺依曼体系结构冯诺依曼结构能干什么? 二.操作系统概念结构图(不完整)为什么要有操作系统? 尝试理解操作系统管理结构图(完整)总结: 三.进程进程是什么?PCB为什么要有PCB? Linux中的PCB进程的task_struc…...
《LlamaIndex 之美》-01-LLM、Prompt、Embedding基础入门
在基于数据构建任何 LLM 应用程序时,选择合适的大型语言模型 (LLM) 是您需要考虑的首要步骤之一。 LLM 是 LlamaIndex 的核心组成部分。它们可以作为独立模块使用,也可以插入到其他核心 LlamaIndex 模块(索引、检索器…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...

python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...
【决胜公务员考试】求职OMG——见面课测验1
2025最新版!!!6.8截至答题,大家注意呀! 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:( B ) A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
AspectJ 在 Android 中的完整使用指南
一、环境配置(Gradle 7.0 适配) 1. 项目级 build.gradle // 注意:沪江插件已停更,推荐官方兼容方案 buildscript {dependencies {classpath org.aspectj:aspectjtools:1.9.9.1 // AspectJ 工具} } 2. 模块级 build.gradle plu…...