【JavaEE】网络编程示例1-UDP套接字数据报编程 == 一发一收

简介: JavaEE & 网络编程示例1 & UDP套接字数据报编程 ==> 一发一收

JavaEE & 网络编程示例1 & UDP套接字数据报编程 ==> 一发一收

1. 协议分层(回顾)

应用层

应用程序所在(程序员),数据的用途

传输层

关注传输过程的起点和终点

网络层

负责整个传输过程的路径规划

数据链路层

针对两个相邻节点之间的数据传输

物理层

硬件设备,基础设施

对于2 和 3 是操作系统内核封装的


对于4 和 5 是硬件和驱动控制的


一般程序员只需要关注1 和 2 即可~

毕竟 1 要传出去或者接受要经过 2


eb35ba9f8021429c836b0d1b0df4603a.png

2. 套接字 Socket

程序员编写网络程序主要编写的是应用层代码


那么,我们就需要第下层协议的提供服务,即 应用层调用传输层提供的API


socket API,网络编程的重要API

socket - 插座,不要纠结名词,用就是了~

这些API是C / C++ 风格的,因为操作系统本身就是C / C++ 写的


JDK针对这些API,封装成Java风格的API

Java程序员这需要正常使用这些API就足够了~

系统给咱们提供了两组socket API


基于UDP的API

基于TCP的API

Destination User Prompter


Transmission Control Protocol


2.1 UDP与TCP两组协议的主要区别

这两个协议有各自的特点~

当然还有其他特点,不做细讲~

2.1.1 UDP无连接,TCP有链接

连接:是一种抽象的连接

就比如说谈恋爱和结婚,结婚就是一种有效的抽象连接


通信双方都隆重地记录了对方的信息~

如果我们的两台机器在通信的时候,需要单独保存记录两台机器的信息就是有连接,不需要则是无连接


注意:不代表无连接就没用到对方的信息,而是只是用到,就仅仅是用到

短期恋爱~

小例子:


DUP无连接

发送就完事了,不需要连接

e6bfa88fed814941a04c2f6500c04ccb.png


TCP有连接:

先连接才能通信

496abc5ae58b44869da49d78fb7a7e8f.png

2.1.2 UDP不可靠传输,TCP可靠传输

可靠传输 不代表百分百能够有效传输,但是会尽力的传输~!

传没传成功,是可以心知肚明的

不可靠传输 则代表,“无所谓,你收不到不是我的锅“

以上面的那个例子继续说:


DUP不可靠传输

我发了就发了,并不在意对方收没收到

我还记得我高中的时候,老人机发短信给我老爸,叫他来学校载我,结果我不知道我爸没收到,导致我等了2 - 3小时 T.T


a874feef019f4cfb9b82a7c4deb83974.png


TCP可靠传输

不说每次都能通信,但是我一定能知道有没有成功



2.1.3 UDP面向数据报,TCP面向字节流

这个跟IO操作的字符流字节流是相似的~

TCP面向字节流:


数据传输以字节为基本单位,读写方便灵活

不在本章讲解


bef44d7e1e1f40239a1b9db42d24d553.png

UDP面向数据报:


数据运算是以一个UDP数据报为基本单位(待会儿的重点)

读写操作不大灵活

d0a3c49a27fd4a74af16a01087a6d1e3.png


2.1.4 UDP与TCP 全双工

单双工:一条路径,单向通信


一边通信完了,另一边才能过去

全双工:一条路径,双向通信


这一边朝另一边,另一边朝这一边,是不需要等的

除非另一边需要这一边的数据作为前提~

例如马路:



对于单双工

c0cc79764f124f048fddeed1b930c485.png


对于全双工

则很有秩序~

而两种协议都是全双工的,所以不用操心~

d90e67eaa8614578a73b964d56ccd525.png


3. 网络编程示例1 ==> 一发一收

UDP要比TCP简单,先难后易

接受新知识的过程可能会很困难,但是这也算是固定写法

熟练最重要!!!

TCP将在后续文章讲到!

这是本文章重点!

3.1 DatagramSocket 与 DatagramPacket

ed78534d9d7040b5980072e801966040.png


Socket ==> 数据报的Socket对象

Packet ==> 这个对象就是一个UDP数据报

71c7dc483b234cd9ab27d02d07334f9a.png


DUP数据运算的基本单位


3.1.1 Socket对象

在文件操作系统中,在文件操作的 时候提到,不是目录不是普通文件的文件


这样特殊的文件有很多,其中就有socket文件

而一个Socket对象就对应一个socket文件~

而socket文件并非对应到硬盘的某一个存储区,而是对应到网卡的一个硬件设备


打开命令行(win + R + cmd)输入ipconfig:


有线网卡


e28984bcc170412c8a46ccff30386439.png

无线网卡:


3e6e45a5eeae4f1ea76e0e6580b268ba.png

一般网卡都是集成在主板上面的


caf5665fdc36deb261318f3206823f33.jpg

文件:


广义:指代系统资源

计算机上的 软件 / 硬件

操作系统的基本设计思想: “一切皆文件”【简化逻辑】

狭义:指代硬盘上的一块数据存储区域

所以,要相进行网络通信,就需要socket文件对应的这个对象(内存中的变量)去搞事情,从而间接操控网卡


输入信息到Socket对象里,就相当于输入信息到socket文件里,就相当于通过网卡发送信息

提取Socket对象里的信息,就相当于读取socket文件里的信息,就相当于通过网卡接受信息

3.1.2 DatagramSocket的一些方法

方法名 方法说明

DatagramSocket() 创建一个Socket,绑定本机任意一个空闲的端口

DatagramSocket(int port) 创建一个Socket,绑定指定的端口(port)

对于不带参数的构造方法,一般用于客户端

系统分配一个端口~

对于待参数的构造方法,一般用于服务端

小例子:

08e102ef38c34ff8a0d7800c33aa65f7.png


6813a6d599974f8f83b7deb5704cce79.png



方法名 方法说明

void receive(DatagramPacket p) 接受数据报并读取到已有数据报

void send(DatagramPacket p) 发送数据报

void close() 关闭socket文件(避免文件资源泄露,但是很少有关闭的时候,这也符合实际情况)

不纸上谈兵了,等一下实战你就懂了!

3.1.3 DatagramPacket的一些方法

本体:


方法名 方法说明

DatagramPacket(byte[] buf, int length) 成员buf取参数字节数组的头开始,长度length的部分

DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 成员buf取参数为字节数组的头开始长度length的部分,并且传入offset(缓冲区偏移量)和socket地址

DatagramPacket(byte[] buf, int length, InetAddress address, int port) 成员buf取参数为字节数组的头开始长度length的部分,并传入包装IP的InetAddress对象,和端口号

对于不带地址的版本:一般就是接受消息的

对于带地址的版本:一般就是用来发送消息的

这个地址包括目的地的IP和端口号~

IP — 确认电脑

端口号port — 确定应用程序

对于第三个构造方法,一般也用于发送信息给服务器的~

InetAddress是对服务器IP地址的包装

端口号代表服务器程序所在的“位置”

方法名 方法说明

InetAddress getAddress() 获取客户端or服务器的IP地址

int getPort() 获取客户端or服务器的端口号

byte[] getData() 获取数据报里的数据

不纸上谈兵了,等一下实战你就懂了!

3.2 基于UDP 的 Socket 写一个简单的客户端服务器程序



73a2294fc9a148b69690fde417774417.png



13376a6140514dd1b31ca12db75b4ee6.png

578cd7c751ea47c398570b4c575a2b2a.png

回显服务器(echo server)

即,客户端发起的请求,服务器响应一个一模一样的响应

请求就是“没有请求”

e3ef08fa8e90411f845538cd26724617.png


就像这样,老板没给我做,给我回了句一模一样的话

接下来就是书写代码的环节了!


第一遍不懂很正常,最终的总结分析可能会对你有很大帮助!

3.2.1 服务器

三个核心工作:


读取请求并解析

根据请求求得对应响应(回显服务器 无此操作)

把响应返回给客户端

构建一个Socket对象

14165815d49e465487c11360806b88ce.png


写一个构造方法


服务器的固定端口!

要处理异常,因为并不是每一次都能绑定成功对应的端口号~

此端口号被占用,就会出错!

在一个主机里,一个端口在同一时刻只能被一个进程绑定

public UDPEchoServer(int port) throws SocketException {
        this.socket = new DatagramSocket(port);
    }


启动服务器的主方法

public void start() {
    System.out.println("启动服务器成功");
    //服务器一直工作 或者 等待客户端请求
    //所以说才很少关闭~
    while(true) {
        //做那三件事!
    }
}


3.2.1.1 读取请求并解析

再次重点强调【数据报】是什么


数据报是一个对象,而服务器要响应的是里面的【数据String】~

数据报为了确定发送对象和确定身份,增加了很多属性和东西~


7f2b17c819cc485f88af02de79bb3c74.png

而我们只需要用socket对象与网卡进行联系,这样就能实现应用层和传输层的数据交换~


而UDP协议,数据传输的基本单位就是【数据报】!

994547698cdd4bfdb739f17ee170ea43.png



public void start() throws IOException {
    System.out.println("启动服务器成功");
    //服务器一直工作 或者 等待客户端请求
    while(true) {
        DatagramPacket request = new DatagramPacket(new byte[1024], 1024);
        //****************  自带饭盒 ****************
        socket.receive(request);//request --- 载体
        //io操作都可能会有IOException异常
        //盛饭,从网卡里面拿的请求,将其录入已存在的数据报里
        String request = new String(requestPacket.getData(), 0,                                      requestPacket.getLength());
    }
}

34cba2274ccc46adaf1bd96434ec4a72.png

Java中的“二进制数据”,可以通过这样构造字符串去解析~

解析utf8编码 -------- 三个字节 ==> 一个字符

解析二进制数据不要与unicode混了~

Unicode跟char类型有关~ 两个字节

4daab30c88764d94a0bd626aea807e76.png


死循环是因为一个服务器无时无刻都要尝试获取请求~


输出型参数:

指的是方法并没有返回一个值,而是将值录入到参数里。起到返回的作用

不用申请多的空间,也不需要拷贝一份返回并修改原指向

例如Set的对象里有一个toArray(T[] ts)方法

这个方法也用到了输出型参数

37496c9147114018b66a41fe30e290f6.png


再例如字符串转字符数组:


6513f7d2f6cd4725ac2c53848d44ee7a.png



public String process(String request) {
    //回显服务器直接返回原值~
    return request;
}

此时,如果还没有客户端发来的数据,咋办?


receive阻塞等待就行了

直到客户端发来请求

有点类似于阻塞队列~

3.2.1.2 计算请求信息为响应信息

String response = process(request);
//计算该字符串的响应



3.2.1.3 将响应信息打包成【数据报】

DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
        response.getBytes().length,
        requestPacket.getSocketAddress());


getSocketAddress ==> 数据报里的客户端主机IP
* 传给客户端得转化为数据报才行
* 而计算数据报的信息计算只能以字符串为对象
3.2.1.4 响应数据报信息发送给客户端
socket.send(responsePacket);
//发送数学报,数据报有客户端的信息,所以可以具体的转发到对方机器
//响应


3.2.1.5 打印日志

System.out.printf("客户端[%s, %d], 发来请求[request]:%s, 其将收到响应[response]:%s\n",
        requestPacket.getAddress(), requestPacket.getPort(),
        request, response);


3.2.1.6 图片分析

7c9e8067a28f4e8598ffd03282e43bda.png


3.2.2 客户端

三个核心工作:


输入台输入请求核心信息,并打包成数据报

发送数据报给服务器

等待服务器响应

public class UDPEchoClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;
}


客户端一些必备的属性

自己的socket对象,只不过端口号可以随机~

服务器的IP和端口 — 决定了发送请求的对象!

//确定服务器
public UDPEchoClient(String serverIP, int serverPort) throws SocketException {
    this.socket = new DatagramSocket();
    this.serverIP = serverIP;
    this.serverPort = serverPort;


构造方法~

传入服务器信息~

socket对象本身就自动获得该机器的IP

经过socket对象的方法,数据报也会染上socket对象的信息也就是发送方的信息~

也就是说

在服务器视角,收到的请求数据报是有客户端的地址的,而客户端发出需要有服务器的地址

在客户端视角,收到的响应数据报是有服务器的地址的,而服务器发出需要有客户端的地址

socket对象操作默认填入socket对象的信息~

3.2.2.1 控制台输入请求

public void start() throws IOException {
    //客户端输入信息
    Scanner scanner = new Scanner(System.in);
    while(true) {
        System.out.print("-> ");
        String request = scanner.nextLine();
        //next方法以空格或者回车分割!
        //控制台输入数据报的【主信息】
    }
}


死循环 ==> 客户端无时无刻都可以发送请求

3.2.2.2 请求信息打包成【数据报】

现在可没有现成的数据报来获取IP和端口号地址~

这里需要可以利用这个构造方法~


InetAddress对象就是IP的一种包装~


InetAddress.getByName,打包对应的IP地址


这里传入了serverIP,即服务器IP


不用理解太深,用就是了


750fbedaef9f4e149b514ce3eee07fd7.png


DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
        request.getBytes().length,
        InetAddress.getByName(serverIP), serverPort);
//打包信息成数据报
//根据ip打包成InetAddress对象

4124c6a9a2684016a06f405b7da9b2f7.png



3.2.2.3 通过socket对象将【数据报】发送给服务器

socket.send(requestPacket);
//发送给服务器


3.2.2.4 等待服务器响应

DatagramPacket responsePacket = new DatagramPacket(new byte[1024], 1024);
//等待服务器返回响应
//而两个机器之间是通过数据报传输
socket.receive(responsePacket);


做好“饭盒” - 【空数据报】,服务器一旦返回响应,就接下~

同样的,服务器返回前,要阻塞等待~


3.2.2.5 提取数据报信息并打印日志

String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
//获取数据报里面的响应信息!
System.out.printf("服务器[%s, %d], 收到请求[request]:%s, 发来响应[response]:%s\n", serverIP,
        serverPort, request, response);
//打印日志


获取【数据报】里的“核心数据”,做成字符串~


32523068bc3f4e9cb111356b26bbc82b.png

3.2.2.6 图片分析

c73f0cfb1dab483488a1354aaa4552e6.png


3.2.3 测试与总结

在服务器里,有一个main线程:

public static void main(String[] args) throws IOException {
    UDPEchoServer udpEchoServer = new UDPEchoServer(9090);
    udpEchoServer.start();
}


在客户端也有一个main线程:

public static void main(String[] args) throws IOException {
    UDPEchoClient udpEchoClient = new UDPEchoClient("10.61.10.239", 9090);
    udpEchoClient.start();
}


对,没错,这是两个进程!


服务器端口号9090是我随便给的!

要对应好!

服务器IP要自己去找!

win + R + cmd + ipconfig

e07a1e57d59f4a2b9df684457b44eaa3.png



运行测试:


47f95c6a12e440cfbe0cfa32dcf78580.gif


f1ea07c961df45d28773b58e7832a6ae.png


总结图示:

79558db01c454bc8b8ec608d093d645a.png



当然可以将服务器打包成jar包导入你的虚拟机

那么别人就可能通过客户端代码发送请求给你了~

不做演示~

3.3 socket文件怎么存储数据的

3120857480984a5481ee06dbd3170a18.png

目录
相关文章
|
2天前
|
机器学习/深度学习 算法 数据可视化
m基于PSO-LSTM粒子群优化长短记忆网络的电力负荷数据预测算法matlab仿真
在MATLAB 2022a中,应用PSO优化的LSTM模型提升了电力负荷预测效果。优化前预测波动大,优化后预测更稳定。PSO借鉴群体智能,寻找LSTM超参数(如学习率、隐藏层大小)的最优组合,以最小化误差。LSTM通过门控机制处理序列数据。代码显示了模型训练、预测及误差可视化过程。经过优化,模型性能得到改善。
16 6
|
5天前
|
数据采集 存储 数据挖掘
Python网络爬虫实战:抓取并分析网页数据
使用Python的`requests`和`BeautifulSoup`,本文演示了一个简单的网络爬虫,抓取天气网站数据并进行分析。步骤包括发送HTTP请求获取HTML,解析HTML提取温度和湿度信息,以及计算平均温度。注意事项涉及遵守robots.txt、控制请求频率及处理动态内容。此基础爬虫展示了数据自动收集和初步分析的基础流程。【6月更文挑战第14天】
72 9
|
4天前
|
存储 安全 网络安全
云计算与网络安全:保护数据的关键前沿
在信息化社会中,云计算技术的快速发展为企业和个人提供了前所未有的便利。然而,随着云服务的普及,网络安全和信息安全问题也日益凸显。本文探讨了云计算中的网络安全挑战,并介绍了一些关键技术和策略,以保障云环境中的数据安全。
16 4
|
12天前
|
数据采集 DataWorks 安全
DataWorks产品使用合集之如何拉取经典网络的数据
DataWorks作为一站式的数据开发与治理平台,提供了从数据采集、清洗、开发、调度、服务化、质量监控到安全管理的全套解决方案,帮助企业构建高效、规范、安全的大数据处理体系。以下是对DataWorks产品使用合集的概述,涵盖数据处理的各个环节。
|
9天前
|
存储 XML 数据处理
Python网络实践:去哪儿旅游数据爬取指南
Python网络实践:去哪儿旅游数据爬取指南
|
12天前
|
分布式计算 NoSQL 大数据
MaxCompute产品使用合集之自定义udf连接云上vpc网络的redis获取数据的步骤是什么
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
15天前
网络编程中的互联网协议 , IP地址 , 域名 , 端口 , 架构 , 网页数据请求 , 响应码
网络编程中的互联网协议 , IP地址 , 域名 , 端口 , 架构 , 网页数据请求 , 响应码
|
16天前
|
移动开发 网络协议 视频直播
25.Python 网络编程:TCP和UDP编程
25.Python 网络编程:TCP和UDP编程
19 2
|
8天前
|
机器学习/深度学习 算法
基于蛙跳优化的神经网络数据预测matlab仿真
使用MATLAB2022a,应用蛙跳优化算法(SFLA)调整神经网络权重,提升预测精度,输出预测曲线。神经网络结合输入、隐藏和输出层进行预测,蛙跳算法模仿蛙群觅食行为优化权重和阈值。算法流程包括蛙群初始化、子群划分、局部搜索及适应度更新,直至满足停止条件。优化后的神经网络能提升预测性能。
|
8天前
|
机器学习/深度学习 算法
m基于PSO-GRU粒子群优化长门控循环单元网络的电力负荷数据预测算法matlab仿真
摘要: 在MATLAB 2022a中,对比了电力负荷预测算法优化前后的效果。优化前为"Ttttttt111222",优化后为"Tttttttt333444",明显改进体现为"Tttttttttt5555"。该算法结合了粒子群优化(PSO)和长门控循环单元(GRU)网络,利用PSO优化GRU的超参数,提升预测准确性和稳定性。PSO模仿鸟群行为寻找最优解,而GRU通过更新门和重置门处理长期依赖问题。核心MATLAB程序展示了训练和预测过程,包括使用'adam'优化器和超参数调整,最终评估并保存预测结果。
15 0