【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 模块(索引、检索器…...
wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
地震勘探——干扰波识别、井中地震时距曲线特点
目录 干扰波识别反射波地震勘探的干扰波 井中地震时距曲线特点 干扰波识别 有效波:可以用来解决所提出的地质任务的波;干扰波:所有妨碍辨认、追踪有效波的其他波。 地震勘探中,有效波和干扰波是相对的。例如,在反射波…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
QT: `long long` 类型转换为 `QString` 2025.6.5
在 Qt 中,将 long long 类型转换为 QString 可以通过以下两种常用方法实现: 方法 1:使用 QString::number() 直接调用 QString 的静态方法 number(),将数值转换为字符串: long long value 1234567890123456789LL; …...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
使用Spring AI和MCP协议构建图片搜索服务
目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式(本地调用) SSE模式(远程调用) 4. 注册工具提…...
Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...
R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...





