本篇会加入个人的所谓鱼式疯言
❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言
而是理解过并总结出来通俗易懂的大白话,
小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.
🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!
引言
在这个信息爆炸的时代,数据传输的速度和效率比以往任何时候都更加重要。想象一下,你正在观看一场在线直播的体育赛事,突然画面卡顿,数据包丢失——这可能是由于TCP协议的重传机制导致的延迟。
但如果你使用的是 UDP,情况可能会完全不同。UDP,即用户数据报协议,以其轻量级和低延迟的特性,在网络编程中扮演着重要角色。本文将深入探讨UDP的工作原理,以及它如何为现代网络通信带来革命性的变化。
目录
- Udp与Tcp 协议
- Udp服务器的实现过程及原理
- Udp客户端的实现过程及原理
- 回显服务器的原理剖析及扩展字典服务器功能
一. Udp 与 Tcp 协议
1. Udp 与 Tcp 的初识
Udp 和 Tcp 都是 Tcp / IP 五层协议中的 第四层:
传输层
, 主要提供在不同主机上提供进程和进程的 传输服务 , 主要还是关注传输的 起点和终点 。
2. Udp 的特点 和 Tcp的特点
Udp: 无连接, 不可靠, 面向
数据报
, 全双工。
Tcp: 有连接, 可靠, 面向
字节流
, 全双工
连接性:连接的含义: 不是实际意义上的两根线连起来,而是一种 抽象的连接 , 就是说通信双方都保存着对方的 信息(IP地址, 端口号)对于Udp 来说是无连接的,也就是
没有
保存 对方信息的一种连接特性。对于Tcp 来说是有连接的, 也就是保存着
对方信息 的一种连接特性。可靠性 : 对于网络通讯来说可靠 不是百分百通信, 而不丢失数据 。 可靠性的关键就在于当 数据发送错误或出现数据丢失 的情况, 是否会进行 >
> 重传>
> 数据。对于 Tcp 来说, 是有 应答响应和延时重传机制的(重点内容后面文章详解), 当网络数据发生影响时, 就会进行重传
。 防止数据的丢失 。对于 Udp 来说, 是没有的
, 当网络通信出现问题时, 就会进行直接把这段数据直接丢弃, 不会发生重传 。面向数据报与面向字节流: 这是两次不同协议的 传输单位 的不同对于Tcp 来说 , 面向字节流就等同于一个字节一个字节传输好比现有一堆数据, 总有二百个字节单位的数据如果你一个一个字节的传输, 需要传输两百次;如果你十个十个字节的传输, 需要传输二十次;如果你二十个字节的传输, 需要传输十次;如果你一百个字节的传输, 就需要传输两次;如果你二百个字节的传输, 就需要传输一次。对于Udp 来说, 是面向数据报的, 这里的数据报还比挖菜需要用锄头, 砍柴需要用斧头一样, 是一种
专门
为网络通信传输构造的一种 特殊结构的传输单位 。我们只需要构造好数据报
, 把需要传输的数据当 成一个整体 打包成数据报
即可。全双工与半双工 : 双工本质上就是一种 传输的方向 , 无论是Tcp 和 Udp , 都是全双工, 其含义就是,无论对于这两种协议部署到主机上, 既可以 >
> 发送数据>
> , 也可以 >> 接受数据>
> , 既可以 >> 发送请求>
> , 也可以 >> 对请求做出响应>
> 。 可以认为是一种双方向的 。> 而半双工就是部署好协议之后, 这个通信设备要么 只能接受数据 , 要么只能发送数据, 而 不能同时接受数据和发送数据, 是以一种 >> 单向>
> 的形式传输。
二. Udp服务器的实现过程及原理
1. 引入
介绍完Tcp和Udp的特点之后,下面就开始上场本篇文章的核心内容,带着小伙伴们一起实践利用 Udp 协议写一个 回显服务器程序 。
什么是回显???
就是这个服务器响应给客户端的是 客户端自身发来的请求 , 服务器这边不做业务/ 逻辑上 的处理, 而是直接把
原请求数据
响应返回给客户端。
对于Udp 来说, 如果需要进行网络通信就需要调用
系统原生api
来进行实现 , 就需要了解
系统原生api
的使用细节, 但对于Java程序猿来说, JDK早已把 api 进行封装, 封装成 两个类: DatagramSocket , DatagramPacket 。 这两个类都来自于
Java.net
这个包中。
DatagramSocket 相关方法:
上述 对
DAtagramSocket
实例化一个
Socket
对象时, 我们就是利用这个
Socket 对象
来对 网卡进行操作 , 从而进行 网络通信的必要操作 。
DatagramPacket 相关方法:
而
DatagramPacket
则是上面谈及的数据报, 每实例化一个数据报时, 就要传入对于的
byte[]
数组作为参数, 打包成
一个整体的数据报单元
进行传输。
想必小伙伴们应该还没有理解吧, 下面的原理部署和代码演示讲带着大伙熟悉这些方法的使用 💖 💖 💖 💖 💖
2. 服务器端代码演示
packagenetwork;importjava.io.IOException;importjava.net.DatagramPacket;importjava.net.DatagramSocket;importjava.net.SocketException;publicclassMyServer{// 定义一个 数据包插口privateDatagramSocket socker =null;// 构造方法publicMyServer(int port)throwsSocketException{// 进行进程和 端口号的连接
socker =newDatagramSocket(port);}publicvoidstart()throwsIOException{while(true){System.out.println("服务器开始运行...");// 打包数据包基本单位DatagramPacket requestPacket =newDatagramPacket(newbyte[4096],4096);// 接受客户端发来的数据
socker.receive(requestPacket);// 转为成字符串打印日志String request =newString(requestPacket.getData(),0, requestPacket.getLength());// 执行业务逻辑并对客户端进行响应String response =process(request);// 打包一组响应的数据包// 注意这里要带上对应客户端输入的ip地址和端口号DatagramPacket responsePacket =newDatagramPacket(response.getBytes(),0, response.getBytes().length,
requestPacket.getSocketAddress());// 进行响应回服务器中
socker.send(responsePacket);// 打印日志System.out.printf("[ip地址为:%s, %s,端口号为:%d, %d 客户端的的需求的为: %s, 服务器的响应为: %s]\n",
requestPacket.getAddress(),responsePacket.getAddress(), responsePacket.getPort(),requestPacket.getPort(), request, response);}}// 业务逻辑的方法publicStringprocess(String request){return request;}publicstaticvoidmain(String[] args)throwsIOException{MyServer myServer =newMyServer(9090);
myServer.start();}}
3. 服务器端代码流程讲解
对于服务器这端来说:
整体 分为五部:
- 实例化
DatagramSocket
并以端口号作为构造方法的参数
建立 端口号与进程 的连接。
// 定义一个 数据包插口privateDatagramSocket socker =null;// 构造方法publicMyServer(int port)throwsSocketException{// 进行进程和 端口号的连接
socker =newDatagramSocket(port);}
- 打包一个数据包用来
接收客户端
发来的 请求。
// 打包数据包基本单位DatagramPacket requestPacket =newDatagramPacket(newbyte[4096],4096);// 接受客户端发来的数据
socker.receive(requestPacket);
- 处理一定的业务逻辑, 由于我们这里是
回显服务器
,只返回请求结果就是为 服务器响应的内容 即可。
// 执行业务逻辑并对客户端进行响应String response =process(request);// 业务逻辑的方法publicStringprocess(String request){return request;}
- 构造一个
数据包
(带上效应的内容,长度, 以及地址) 用于把 服务器效应发送回
服务器。
// 打包一组响应的数据包// 注意这里要带上对应客户端输入的ip地址和端口号DatagramPacket responsePacket =newDatagramPacket(response.getBytes(),0, response.getBytes().length,
requestPacket.getSocketAddress());// 进行响应回服务器中
socker.send(responsePacket);
- 将 客户端的
IP地址
, 客户端的端口号
,请求
,效应
都 打印 出来。
// 打印日志System.out.printf("[ip地址为:%s,%s,端口号为:%d,%d
客户端的的需求的为:%s, 服务器的响应为:%s]\n",
requestPacket.getAddress(),responsePacket.getAddress(),
responsePacket.getPort(),requestPacket.getPort(), request, response);}}
鱼式疯言
- 由于
网络通信
需要的是 服务器和客户端同时交互
才能展示效果,所以小伙伴们一定要记住只有两台机子以上才能完成回显服务器
的实现。
- 在
端口号与进程
进行连接时, 需要注意的是:一个 进程能连接多个
端口号但是一个
端口号只能连接 一个 进程。
- 在获取 IP地址 和 端口号 打印时, 就需要
三. Udp客户端的实现过程及原理
Udp 的实现 还是利用
DatagramSocket
,
DatagramPacket
两个类来实现, 大体上的实现过程是
相似的
,但有 细微之处不相同 。
下面我们来看看吧 💖 💖 💖 💖
1. 客户端的代码展示
packagenetwork;importjava.io.IOException;importjava.net.DatagramPacket;importjava.net.DatagramSocket;importjava.net.InetAddress;importjava.net.SocketException;importjava.util.Scanner;publicclassMyClient{// 服务器ipprivateString serverIp ;// 服务器的端口号privateint serverPort;// 创建一个客户端的插口privateDatagramSocket clientSocket =null;publicMyClient(String serverIp ,int serverPort)throwsSocketException{// 对该服务器的ip 和端口号进行赋值this.serverIp = serverIp;this.serverPort = serverPort;// 连接时,无须指定参数
clientSocket =newDatagramSocket();}publicvoidstart()throwsIOException{while(true){System.out.println("客户端开始运行...");Scanner in=newScanner(System.in);System.out.print("请输入你的需求: ");// 输入String request = in.next();// 打包成 数据量基本单位// 并指定 ip 和 端口号DatagramPacket requestPacket =newDatagramPacket(request.getBytes(),
request.getBytes().length,InetAddress.getByName(this.serverIp),this.serverPort);// 发送给服务器
clientSocket.send(requestPacket);// 构造一个数据包基本单位接受服务器的响应DatagramPacket receivePacket =newDatagramPacket(newbyte[4096],4096);// 开始接收
clientSocket.receive(receivePacket);System.out.println("最终服务器的效应为: ");// 输出日志String receive =newString(receivePacket.getData(),0, receivePacket.getLength());System.out.println(receive);}}publicstaticvoidmain(String[] args)throwsIOException{MyClient myClient =newMyClient("127.0.0.1",9090);
myClient.start();}}
2. 客户端的代码流程讲解
- 先实例化一个
Socket 对象
, 并得到 需要发送服务器
的 IP地址和端口号 。
publicMyClient(String serverIp ,int serverPort)throwsSocketException{// 对该服务器的ip 和端口号进行赋值this.serverIp = serverIp;this.serverPort = serverPort;// 连接时,无须指定参数
clientSocket =newDatagramSocket();}
- 在控制台中 输入需求 ,并打包成
数据报
(带上数据内容, IP地址, 以及端口号) , 然后利用 Socket 对象进行发送。
System.out.println("客户端开始运行...");Scanner in=newScanner(System.in);System.out.print("请输入你的需求: ");// 输入String request = in.next();// 打包成 数据量基本单位// 并指定 ip 和 端口号DatagramPacket requestPacket =newDatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(this.serverIp),this.serverPort);// 发送给服务器
clientSocket.send(requestPacket);
- 构造一个 数据报 用来接受服务器
返回的响应
// 构造一个数据包基本单位接受服务器的响应DatagramPacket receivePacket =newDatagramPacket(newbyte[4096],4096);// 开始接收
clientSocket.receive(receivePacket);
- 打印 服务器响应 的日志
// 输出日志
String receive =new String(receivePacket.getData(),
0, receivePacket.getLength());
System.out.println(receive);
鱼式疯言
补充细节 :
- 对于客户端这端来说, 当
实例化Socket
时, 是不需要指定端口号
的, 因为系统就根据客户端的空缺的端口号
自动默认分配一个端口号
。 如果 程序猿来 分配分配进程 就有可能造成 某个端口号正在忙碌, 就会出现 一个端口号绑定多个进程 的情况,就会参生BUG
。
- 由于我们传入的IP 地址是 一个字符串 , 我们就需要转换为对于的
点分十进制
的地址表示方式: InetAddress.getByName(this.serverIp)
- 异常
SocketException
属于IOException
的 子类
四. 回显服务器的原理剖析及扩展字典服务器功能
1. 回显服务器的原理剖析
具体
回显服务器
的流程小编用 图示 的方式表示啦,
- 服务端等待客户端发送请求:
- 客户端发送以及阻塞等待:
- 返回客户端的响应:
- 整体的流程:
鱼式疯言
- 从构造数据报的内容,我们可以看出
Udp
是 面向数据报 的特点
- 从每次发送请求,或者返回响应都需要 设定IP地址和端口号 , 可以看出
Udp
无连接需要手动设置 IP 和端口号 的特点。
- 从客户端 既可以发送请求又可以接收响应 , 并且 服务器既可以接收请求,发送响应 , 充分说明 Udp是
全双工传输
的特点。
关于 Udp
不可靠传输
这个特点,这是一个难点也是重点, 小编会在后面的文章中重点详细的
2. 字典服务器功能
服务器:
packagenetwork;importjava.io.IOException;importjava.net.SocketException;importjava.util.HashMap;importjava.util.Map;publicclassMyDicServerextendsMyServer{privateMap<String,String> map =newHashMap<>();publicMyDicServer(int port)throwsSocketException{super(port);
map.put("cat","小猫");
map.put("dog","小狗");
map.put("dusk","小鸭");}@OverridepublicStringprocess(String request){return map.getOrDefault(request,"未知单词");}publicstaticvoidmain(String[] args)throwsIOException{MyServer m =newMyDicServer(9090);
m.start();}}
客户端:
packagenetwork;importjava.io.IOException;importjava.net.DatagramPacket;importjava.net.DatagramSocket;importjava.net.SocketException;publicclassMyServer{// 定义一个 数据包插口privateDatagramSocket socker =null;// 构造方法publicMyServer(int port)throwsSocketException{// 进行进程和 端口号的连接
socker =newDatagramSocket(port);}publicvoidstart()throwsIOException{while(true){System.out.println("服务器开始运行...");// 打包数据包基本单位DatagramPacket requestPacket =newDatagramPacket(newbyte[4096],4096);// 接受客户端发来的数据
socker.receive(requestPacket);// 转为成字符串打印日志String request =newString(requestPacket.getData(),0, requestPacket.getLength());// 执行业务逻辑并对客户端进行响应String response =process(request);// 打包一组响应的数据包// 注意这里要带上对应客户端输入的ip地址和端口号DatagramPacket responsePacket =newDatagramPacket(response.getBytes(),0,
response.getBytes().length,
requestPacket.getSocketAddress());// 进行响应回服务器中
socker.send(responsePacket);// 打印日志System.out.printf("[ip地址为:%s,%s,端口号为:
%d,%d 客户端的的需求的为:%s, 服务器的响应为:%s]\n",
requestPacket.getAddress(),
responsePacket.getAddress(),
responsePacket.getPort(),
requestPacket.getPort(),
request, response);}}// 业务逻辑的方法publicStringprocess(String request){return request;}publicstaticvoidmain(String[] args)throwsIOException{MyServer myServer =newMyServer(9090);
myServer.start();}}
字典服务器小编在这里只是作为扩展内容, 其实操作远不止这里, 至于字典服务器怎么生成的?
其实很简单, 只是在原来的基础上加入了一个
哈希表
进行返回, 即使不理解的小伙伴也无妨, 重要是理解前面Udp 的回显服务器的
实现原理
即可。
总结
- Udp与Tcp 协议 : 主要说明的四种
Udp
和Tcp
不同核心特点 - Udp服务器的实现过程及原理: 先了解 实现回显服务器
Udp
的两个类, 分别是 操作网卡 进行网络通信的DatagramSocket 对象
与实现包装数据的DatagramPacket 数据报
。 并实现了 服务器的代码以及流程讲解。 - Udp客户端的实现过程及原理:实现了
Udp
的客户端代码 , 并且就客户端的特点进行了流程讲解。 - 回显服务器的原理剖析及扩展字典服务器功能 : 从
图示的方式
进行理解回显服务器的原理, 并且扩展了 字典服务器 的内容。
如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正
希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖
版权归原作者 邂逅岁月 所有, 如有侵权,请联系我们删除。