您的位置:首页 > 健康 > 养生 > 新网站百度收录_广告设计公司报价单_中国新闻网发稿_seo云优化平台

新网站百度收录_广告设计公司报价单_中国新闻网发稿_seo云优化平台

2025/4/22 17:16:26 来源:https://blog.csdn.net/2301_78583687/article/details/147287509  浏览:    关键词:新网站百度收录_广告设计公司报价单_中国新闻网发稿_seo云优化平台
新网站百度收录_广告设计公司报价单_中国新闻网发稿_seo云优化平台

目录

一. UDP API

二. UDP回显客户端-服务器

1. 服务器

2. 客户端

3. 客户端-服务器的工作流程


UDP数据报套接字编程是一种基于无连接协议的网络通信方式

一. UDP API

 在网络通信中最重要的硬件设备就是网卡,我们可以将网卡这样的硬件设备抽象为Socket文件

 通过网卡发送数据,可以抽象为写Socket文件

 通过网卡接收数据,可以抽象为读Socket文件

 在这里我们可以理解为对Socket文件进行读写,也就是借助网卡发送和接受数据


在UDP编程中,主要使用两个核心类:DatagramSocket和DatagramPacket

DatagramSocket

DatagramSocket是UDP Socket,负责数据报的发送和接收。

DatagramSocket 构造方法 :

方法说明
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定本机随意分配的一个端口(一般用于客户端)
DatagramSocket(int port)创建一个UDP数据报套接字的Socket,绑定本机指定的端口(一般用于服务端)

 DatagramSocket 方法:

方法说明
void receive(DatagramPacket p)接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacketp)发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

DatagramPacket

DatagramPacket是UDP Socket,用于封装 UDP 数据报的数据内容地址信息

DatagramPacket构造方法:

方法说明
DatagramPacket(byte[] buf, int length)

构造一个DatagramPacket用来接收数据报

第一个参数存放接收的数据,

第二个参数表示接收数据的指定长度

DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)

构造一个DatagramPacket用来发送数据报

第一个参数存放要发送的数据

第二个参数表示起始偏移量

第三个参数表示发送数据的指定长度

第四个参数表示目的主机的IP和端口号

 DatagramPacket方法:

方法签名方法说明
InetAddress getAddress()获取主机IP地址
int getPort()获取主机端口号
byte[] getData()获取数据报中的数据

二. UDP回显客户端-服务器

 回显服务器

回显服务器:不进行任何的业务逻辑,只是将收到的数据显示出来

  • 在网络编程中,我们只需要会使用传输层提供的API,明白网络传输的基本流程即可
  • 传输层会对每一个Socket对象分配独立的缓冲区(操作系统内核中)
  • 网卡收到的数据会层层分用并解析,放入缓冲区中
  • 网络编程本质上是在对缓冲区中的数据进行操作 

1. 服务器

 分配端口号

无论是发送方还是接受方,都必须分配一个端口号

        socket = new DatagramSocket(port);

端口号类似于网络区分进程的身份标识符,在网络通信中,根据端口号确定将数据交给那个进程

注意:

  • 一个端口只能被一个进程绑定,一个进程可以同时绑定多个端口
  • 如果一个端口被多个进程使用,则会抛出异常 

衡量服务器效率

 服务器往往是24小时全天无休运行,一直在循环处理请求并返回响应的过程

一个服务器在单位时间内处理请求和返回响应越多,说明服务器的效率越高


服务器如何处理请求和返回响应?

1)读取请求并解析

(1)构造一个数据报容器

   DatagramPacket requestPacket = new DatagramPacket(new byte[1024],1024);
  •  由于UDP使用数据报传输数据,构造一个数据报容器,将读取的数据放入容器中

(2)读取请求

            socket.receive(requestPacket);
  • 使用receive方法从内核的缓冲区中读取数据报,放入requestPacket容器中
  • UDP数据报中的载荷部分放到了requestPacket的字节数组中,报头中的属性信息也会被保存在requestPacket中
  • 如果缓冲区中没有数据,则会陷入阻塞等待中

(3)将字节数组转换为字符串

            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
  •  getLength()方法:获取字节数组中的有效数据长度(如果全长可能会有很大的空白)
  •  字节数组中可能保存文本数据,也可能保存二进制数据,这里统一使用String来保存

2)根据请求得出响应

 回显服务器:不会处理数据,输入什么就会返回什么

            String response = process(request);

 使用process方法来实现回显功能

    public  String process(String request) {return request;}

 如果想要实现特定的功能,直接在process中实现即可

3)将响应返回客户端

(1)构造数据报 

由于数据格式为UDP数据报,所以将String类型的数据转换成UDP数据报

    DatagramPacket respondPacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
  •  数据报中包含:字节数组,字节数,客户端IP地址和端口号
  • 客户端的IP地址和端口号从接收的请求数据报中获取
  • 将请求中的源ip,源端口,作为响应的目的ip和目的端口

 注意:response.getBytes().length 和 response.length 区别

  •  response.getBytes().length 表示字节数
  • response.length 表示字符数

(2)发送数据报

          socket.send(respondPacket);

 通过使用send()方法将UDP数据包发送出去(send方法不会阻塞等待)


 服务器总代码


import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;//udp服务端
public class UdpEchServer {private DatagramSocket socket = null;//在创建的时候规定端口号public UdpEchServer(int port) throws SocketException {socket = new DatagramSocket(port);}public void start() throws IOException {System.out.println("启动服务器");while(true){//一直在处理请求和发回响应
//            1.读取请求并解析//Udp使用数据报,所以使用DatagramPacketDatagramPacket requestPacket = new DatagramPacket(new byte[1024],1024);//从内核的缓存区中取出数据放入requestPacket中socket.receive(requestPacket);//将requestPacket中的数据(字节数组)转换成String类型String request = new String(requestPacket.getData(),0,requestPacket.getLength());
//            2.根据请求得出响应3String response = process(request);
//            3,将响应返回客户端//继续使用数据报的方式返回//数据报中包含,响应的内容,长度,请求方的地址DatagramPacket respondPacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());socket.send(respondPacket);//打印日志System.out.printf("[客户端IP= %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 {UdpEchServer udpEchServer = new UdpEchServer(9090);udpEchServer.start();}
}
  •  一般服务器需要分配指定的端口(保证端口固定),而客户端则不需要
  • 如果服务器的端口号由系统随机分配,有可能会出现,服务器重启一次,所有的客户端找不到服务器的位置

2. 客户端

 指定IP和端口号

    public UdpEchoClient(String serverIp, int serverPort) throws SocketException {this.serverPort = serverPort;this.serverIp = serverIp;socket = new DatagramSocket();}
  •  客户端需要主动向服务器发送消息,发送消息的前提是知道服务器的位置(IP和端口号)

 客户端如何发送请求和接收响应?

1)获取请求数据

 (1)从控制台输入数据

       Scanner scanner = new Scanner(System.in);while(true){System.out.print("请输入:");
//            1.从控制台中获取发送的请求数据if(!scanner.hasNext()){break;}//将数据转为字符串格式String request = scanner.next();}
  •  使用Scanner输入数据,如果没有输入数据,则会进入阻塞等待

2)发送请求数据报

 (1)构造请求数据报

            DatagramPacket requestPack = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIp),serverPort);
  •  数据报中包含:字节数组,字节数,服务器IP地址和端口号
  • 客户端将数据报发送给服务器,就必须要知道内容和接收的地址
  • InetAddress.getByName(serverIp):将IP 地址字符串解析为InetAddress对象。

(2)发送请求数据报

            socket.send(requestPack);

 调用send()方法,将构造的requestPack数据报(请求数据报)发送出去


3)接收服务器响应

(1)创建一个数据报容器

            //创建一个空的字节数组来接受响应DatagramPacket respondPack = new DatagramPacket(new byte[1024],1024);
  •  构建出响应数据报容器,将接收的响应数据报,放入容器中

(2)接收响应数据报

            socket.receive(respondPack);
  •  通过调用receive()方法,将从内核缓冲区取出的数据报放入respondPack中
  • 当缓冲区中没有数据的时候,会进入阻塞等待

4)显示响应信息

            String respond = new String(respondPack.getData(),0,respondPack.getLength());System.out.println("服务端的回应:"+respond);
  •  将数据报中的字节数组转换为字符串类型,并打印在控制台

客户端总代码

import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp ;private int serverPort;public UdpEchoClient(String serverIp, int serverPort) throws SocketException {this.serverPort = serverPort;this.serverIp = serverIp;socket = new DatagramSocket();}public void start() throws IOException {System.out.println("客户端启动!");Scanner scanner = new Scanner(System.in);while(true){System.out.print("请输入:");
//            1.从控制台中获取发送的请求数据if(!scanner.hasNext()){break;}//将数据转为字符串格式String request = scanner.next();
//            2.将请求数据构造成数据报,并发送//其中数据报中包括,内容,长度,服务端的ip,服务端的端口号DatagramPacket requestPack = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIp),serverPort);//发送请求socket.send(requestPack);
//            3.服务器的响应//创建一个空的字节数组来接受响应DatagramPacket respondPack = new DatagramPacket(new byte[1024],1024);//从缓存区接受数据报保存在respondPack中socket.receive(respondPack);
//            4.将数据报中的内容显示到控制台String respond = new String(respondPack.getData(),0,respondPack.getLength());System.out.println("服务端的回应:"+respond);}}public static void main(String[] args) throws IOException {UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",9090);udpEchoClient.start();}
}

代码中出现的三种构造UDP数据报(DatagramPacket) 

(1)因为接收数据报,构造的数据报容器

            DatagramPacket respondPack = new DatagramPacket(new byte[1024],1024);

(2) 客户端发送请求数据报

            DatagramPacket requestPack = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serverIp),serverPort);

(3)服务器发送响应数据报 

        DatagramPacket respondPacket = new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());
  •  从接收的请求数据报中获取IP和端口号

3. 客户端-服务器的工作流程


 整个过程中,服务器先启动

  1. 服务器启动后,进入while循环,执行receive,由于缓冲区没有数据,故进入阻塞
  2. 客户端启动后,进入while循环,由于没有输入信息,故在hasNext()这里被阻塞
  3. 客户端输入信息后,hasNext()阻塞被取消,将输入的数据构造成数据报,并使用send发送,发送成功后,调用receive()接收响应数据报,由于服务器没有返回响应数据报,故进入阻塞
  4. 服务器的缓冲区收到数据后,从阻塞中唤醒,调用receive()接收客户端的请求数据报,将读到数据报构造成String类型,通过process()方法得到响应字符串,将字符串转换为数据报并使用send发送给客户端
  5. 客户端从receive中返回,将得到的响应数据报转换成String类型,并打印在控制台上

上述的功能一直循环,直到进程销毁


在整个代码中,并没有使用close方法,对于socket对象来说,生命周期应该伴随整个进程,因此进程结束之前,不能提前用 close 关闭 socket 对象,当进程已经结束后,所有的资源自然也就释放了


 点赞的宝子今晚自动触发「躺赢锦鲤」buff! 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com