网络编程 (UDP 和 TCP 介绍和代码实现) [Java EE]

server/2025/3/2 14:26:28/

网络编程基础

网络资源

// 所谓的网络资源, 其实就是在网络中可以获取的各种数据资源, 而所以得网络资源,都是通过网络编程来实现数据传输的

网络编程

// 网络编程, 指网络上的主机, 通过不同的进程, 以编程的方式实现网络通信(网络数据传输)

// 网络编程 就是写一个应用程序, 让这个程序可以使用网络通信, 这里就需要调用传输层提供的api

1. 基本概念

 1.1 发送端和接收端

// 在一次网络数据传输时:

1.1.1 发送端: 数据的发送方进程, 称为发送端. 发送端主机即网络通信中的源主机

1.1.2 接收端: 数据的接收方进程, 称为接收端. 接收端主机即网络通信中的目的主机

1.1.3 收发端: 发送端和接收端两端, 也简称为收发端

// 发送端和接收端只是相对的, 只是一次网络数据传输产生数据流向后的概念

1.2 请求和响应 

// 一般来说, 获取一个网络资源, 设计到两次网络数据传输:

1.2.1 第一次: 请求数据的发送

1.2.2 第二次: 响应数据的发送

1.3 客户端和服务端

1.3.1 服务端: 在常见的网络数据传输场景下, 把提供服务的一方进程, 称为服务端, 可以提供对外服务

1.3.2 获取服务的一方进程, 称为客户端

// 对于服务来说, 一般提供:

// 客户端获取服务资源

// 客户端保存资源在服务端

1.4 常见的客户端

// 最常见的场景, 客户端是指给用户使用的程序, 服务端是提供用户服务的程序:

1.4.1 客户端先发送请求到服务端

1.4.2 服务端根据请求数据, 执行相应的业务处理

1.4.3 服务端返回响应: 发送业务处理结果

1.4.4 客户端根据响应数据, 展示处理结果

UDP 数据报套接字 

API 介绍 (socket api)

// 两个核心类

1. DatagramSocket

// 是一个 Socket 对象

// 操作系统, 通过使用文件这样的概念, 来管理一些软硬件资源

// Java 中的 socket 对象, 就对应着系统里的 socket 文件(最终还是要落到网卡) 

// 要进行网络通信, 必须得先有 socket 对象

// DatagramSocket 构造方法:

方法签名方法说明
DatagramSocket()

创建一个 UDP 数据报套接字的 Socket,

绑定到本机任意一个随机端口 (一般用于客户端)

DatagramSocket(int port)

创建出一个 UDP 数据报套接字的 Socket,

绑定到本机指定的端口 (一般用于服务端)

// DatagramSocket 方法:

方法签名方法说明
void receive(DatagramPacket p)

从此套接字接收数据报 (如果

没有接收的数据报, 该方法会阻塞等待)

void send(DatagramPacket p)

从此套接字发送数据报包

(不会阻塞等待, 直接发送)

void close()关闭此数据报套接字

// 客户端使用哪个端口, 系统自动分配

// 服务器使用哪个端口, 手动指定的

2. DatagramPacket

// 表示了一个 UDP 数据报

// 代表了系统中设定的 UDP 数据报的二进制结构

代码实现 UDP 客户端服务器 

1. UDP 的 回显服务器

// 回显服务器: 请求和响应是一样的

// 配合回显客户端使用

public class UdpEchoServer {private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");while (true) {// 1. 读取请求, 并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);String request = new String(requestPacket.getData(),0,requestPacket.getLength());// 2. 根据请求, 计算响应String response = process(request);// 3. 把响应写会客户端DatagramPacket datagramPacket = new DatagramPacket(response.getBytes(),response.getBytes().length, requestPacket.getSocketAddress());socket.send(datagramPacket);System.out.printf("[%s:%d] req: %s, resp: %s \n", requestPacket.getAddress().toString(),requestPacket.getPort(), request, response);}}public String process (String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();}
}

 

2. UDP 的 回显客户端 

public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp;private int serverPort;// 服务器的 IP 和 服务器的端口public UdpEchoClient(String ip, int port) throws SocketException {serverIp = ip;serverPort = port;// 这个 new 操作, 就不再指定端口了, 让系统自动分配一个空闲端口socket = new DatagramSocket();}// 让这个客户端反复的从控制台读取用户输入的内容, 把这个内容构造成 UDP 请求,// 发给服务器, 再读取服务器返回的 UDP 响应// 最终再显示在客户端的屏幕上public void start() throws IOException {Scanner scanner = new Scanner(System.in);System.out.println("客户端启动!");while (true) {// 1. 从控制台读取用户输入的内容System.out.print("-> ");String request = scanner.next();// 2. 构造请求对象, 并发给服务器DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(serverIp),serverPort);socket.send(requestPacket);// 3. 读取服务器的响应, 并解析出响应内容DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);socket.receive((responsePacket));String response = new String(responsePacket.getData(), 0, responsePacket.getLength());// 4. 显示到屏幕上System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);client.start();}
}

 

 3. 翻译服务器

// 翻译服务器的请求是一些英文单词, 响应则是对应的中文翻译

// 因为我们的翻译服务器和之前的回显服务器很多逻辑都很相似, 所以直接继承 (复用)

public class UdpDictServer extends UdpEchoServer{private Map<String, String> dict = new HashMap<>();public UdpDictServer(int port) throws SocketException {super(port);dict.put("cat","小猫");dict.put("dog","小狗");dict.put("pig","小猪");dict.put("fuck","卧槽");}// 是要复用之前的代码, 但是又要做出一些调整public String process(String request) {// 把请求对应单词的翻译给返回回去return dict.getOrDefault(request, "该词没有查询到");}public static void main(String[] args) throws IOException {UdpDictServer server = new UdpDictServer(9090);server.start();}
}

 

TCP 数据报套接字

// TCP 分量要比 UDP 更重, 用更多协议

// 字节流, 一个字节一个字节进行传输的, 一个 TCP 数据报, 就是一个 字节数组 byte[]

API 介绍

1. ServerSocket

// 给服务请求使用的 socket

2. Socket

// 既会给服务器使用, 也会给客户端使用

代码实现 TCP 版本的客户端服务器

1. TCP 回显服务器
public class TcpEchoServer {private ServerSocket serverSocket = null;private ExecutorService service = Executors.newCachedThreadPool();// 这个操作就会绑定端口号public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}// 启动服务器public void start() throws IOException {System.out.println("服务器启动!");while (true) {Socket clientSocket = serverSocket.accept();service.submit(new Runnable() {@Overridepublic void run() {try {processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}}});}}// 通过这个方法来处理一个连接的逻辑private void processConnection(Socket clientSocket) throws IOException {System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress().toString(),clientSocket.getPort());// 接下来就可以读取请求, 根据请求计算响应,返回响应三步走了try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream =clientSocket.getOutputStream()) {while (true) {// 1. 读取请求并解析, 为了方便, 直接使用 ScannerScanner scanner = new Scanner(inputStream);if (!scanner.hasNext()) {// 读取完毕, 客户端下线System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}// 这个代码暗含一个约定, 客户端发过来的请求, 得是文本数据, 同时, 还得带有空白符作为分割 (比如换行这种)String request = scanner.next();// 2. 根据请求计算响应String response = process(request);// 3. 把响应写回个客户端PrintWriter writer = new PrintWriter(outputStream);//  使用 PrintWriter 的 println 方法, 把响应返回给客户端//  用 println, 而不用 print, 就是为了在结尾加一个 \n, 方便客户端读取响应, 使用 scanner.next 读取writer.println(response);//  这里还需要加入一个 "刷新缓冲区" 操作writer.flush();//  日志, 打印当前的请求详情System.out.printf("[%s:%d] req: %s, resp: %s\n ", clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);} 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. TCP 回显客户端

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.printf("客户端启动!\n");Scanner scannerConsole = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){while (true) {// 1. 从控制台输入字符串System.out.printf("->");String request = scannerConsole.next();// 2. 把请求发送给服务器PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);printWriter.flush();// 3. 从服务器读取响应Scanner scannerNetwork = new Scanner(inputStream);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();}
}

UDP 和 TCP 特点对比

// UDP : 无连接, 不可靠传输, 面向数据报, 全双工

// TCP : 有连接, 可靠传输, 面向字节流, 全双工


http://www.ppmy.cn/server/171816.html

相关文章

【含文档+PPT+源码】基于SpringBoot的宠物领养系统设计与实现

项目介绍 本课程演示的是一款 基于SpringBoot的宠物领养系统设计与实现&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 …

GPT-4.5 怎么样?如何升级使用ChatGPTPlus/Pro? GPT-4.5设计目标是成为一款非推理型模型的巅峰之作

GPT-4.5 怎么样&#xff1f;如何升级使用ChatGPTPlus/Pro? GPT-4.5设计目标是成为一款非推理型模型的巅峰之作 今天我们来说说上午发布的GPT-4.5&#xff0c;接下来我们说说GPT4.5到底如何&#xff0c;有哪些功能&#xff1f;有哪些性能提升&#xff1f;怎么快速使用到GPT-4.…

软件测试之白盒测试知识总结

&#x1f345; 点击文末小卡片 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 概念与定义 白盒测试&#xff1a;侧重于系统或部件内部机制的测试&#xff0c;类型分为分支测试&#xff08;判定节点测试&#xff09;、路径测试、语句测试…

第2_3章_入门管理资源服务器

入门 对于某些应用程序&#xff0c;你可以参考以下资源&#xff0c;快速开始使用 Keycloak 授权服务&#xff1a; 在 Wildfly 中保护 JakartaEE 应用程序&#xff08;https://github.com/keycloak/keycloak-quickstarts/tree/latest/jakarta/servlet-authz-client&#xff09…

基于STM32语音识别的智能家居

摘 要 人们对生活水平的需求伴随着科技的日新月异不断提升&#xff0c;尤其是在日渐成熟的物联网驱动下&#xff0c;智能家居系统备受大众关注。因此&#xff0c;设计一套效率高&#xff0c;控制简便&#xff0c;成本低廉&#xff0c;以及能为用户提供舒适、环保的家居环境的智…

DeepSeek 1.5B蒸馏模型的J6部署(Llama方式)

前言 DeepSeek 是一款基于人工智能的搜索引擎&#xff0c;旨在提升用户的搜索体验。它利用先进的自然语言处理技术&#xff0c;通过理解查询的上下文和意图&#xff0c;为用户提供更精确、相关的搜索结果。与传统的搜索引擎不同&#xff0c;DeepSeek 不仅仅依赖于关键词匹配&a…

设计模式-单例、策略、代理、建造、工厂

文章目录 单例设计模式策略模式代理设计模式建造者模式工厂设计模式 单例设计模式 单例设计模式保证全局只有一个实例&#xff0c;通常用于资源的共享&#xff0c;比如 spring 中的 bean 默认 就是单例的&#xff0c;所有类注入的对象都是同一个。 在类中绑定一个静态的资源也…

MDC + TraceId分布式链路追踪

一、核心概念深度解析 1.1 TraceId 的设计哲学 实现意义&#xff1a; 请求全生命周期追踪&#xff1a;在分布式系统中&#xff0c;一个用户请求可能跨越多个服务、线程和中间件。TraceId 就像快递单号&#xff0c;能够串联整个请求链路故障定位效率提升&#xff1a;当系统出…