UDP数据报网络编程(实现简单的回显服务器,客户端)

news/2024/5/18 12:08:12 标签: udp, 服务器, 网络协议, java

       回显服务器表示客户端发的是啥,服务器就返回啥,主要是为了熟悉UDP数据报网络编程的基本步骤

        对于程序的所有分析都写到了代码上

UDP回显服务器代码

java">package UdpEcho;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: wuyulin
 * Date: 2023-08-09
 * Time: 11:52
 */
//UDP回显服务器,客户端发的是啥,服务器就返回啥
//通过UDP回显服务器的实现来简单熟悉创建服务器的API
//我们创建了DatagramSocket类的对象,但是在程序中没有调用close方法关闭该对象
//1.我们整个程序只实例化了一个DatagramSocket类的对象(socket)
//2.socket对象的生命周期非常长,是跟随整个程序的,此时就需要socket对象保持打开的状态
//3.socket对象->系统中的socket文件->文件描述符(进程的pcb(进程控制块)的属性),最主要的目标是为了释放文件描述符表中的文件描述符,才要关闭socket对象
//而进程结束,就把pcb回收,里面的文件描述符表自然也被销毁了
//当程序中有多个socket对象,socket对象的生命周期较短,需要频繁的创建和释放,一定要记得close
public class UdpEchoServer {
    //对于实现UDP服务器DatagramSocket是不可或缺的类
    //要通过DatagramSocket类的对象(网卡对象)来进行客户端与服务器之间的数据交换
    private DatagramSocket socket=null;
    //在实例化UDP回显服务器的时候就要实例化一个DatagramSocket对象(网卡对象)
    //对于服务器我们在实例化DatagramSocket对象时需要指明服务器的端口号,方便客户端寻找
    public UdpEchoServer(int port) throws SocketException {
        socket=new DatagramSocket(port);
    }

    //定义一个start方法来启动UDP回显服务器
    public void start() throws IOException {
        System.out.println("服务器启动");
        //服务器启动以后要一直去接收客户端传来的请求,并进行处理以及回应
        while (true){
            //服务器在启动以后要处理的三件核心环节
            //1.读取客户端传来的请求,并解析(客户端传来的请求是一个二进制数组,要根据实际情况解析为字符串或数字等等)
            //UDP服务器进行发送和接收的数据单位是UDP数据报(DatagramPacket)
            //DatagramPacket数据报类型有两个参数,当DatagramPacket类型的对象用于接收数据,就不需要提供ip地址和端口号(SocketAddress)
            DatagramPacket requestPacket=new DatagramPacket(new byte[4080],4080);
            //客户端传来的请求(数据报)就会存储到DatagramPacket类型的对象requestPacket中
            //receive方法自带阻塞等待,当服务器没有接受到客户端传来的请求时,在receive方法这里就会进入阻塞等待,直到客户端传来请求为止
            socket.receive(requestPacket);
            //2.根据请求,计算出响应(这个是在实际工作中我们最主要编写的逻辑)
            //由于回显服务器对数据的处理很简单(客户端发的是啥,服务器就返回啥)
            //所以我们将客户端发出的请求转换为字符串再把字符串传递给客户端即可
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            String repose=handle(request);
            //3.把响应发送给客户端
            //发送的响应也是DatagramPacket(UDP数据报)类型
            //由于要将响应发送给客户端,所以需要知道客户端的ip地址和端口号(SocketAddress类型)
            //requestPacket(接收客户端传来的请求)中含有服务器和客户端的ip地址和端口号
            //可以通过getSocketAddress方法获得客户端的ip地址和端口号(SocketAddress类)
            DatagramPacket reponsePacket=new DatagramPacket(repose.getBytes(),repose.getBytes().length,requestPacket.getSocketAddress());
            socket.send(reponsePacket);

            //服务器就完成了接收数据,处理数据,发送数据的过程
            //记录日志,方便观察程序执行效果
            //requestPacket是客户端传给服务器的请求报,所以其中有客户端和服务器的ip地址和端口号
            //通过getAddress方法获得客户端的ip地址,getPort方法获得客户端的端口号
            System.out.printf("[%s,%d] request:%s repose:%s\n",requestPacket.getAddress().toString(),
                    requestPacket.getPort(),request,repose);
        }
    }

    //对客户端传来的请求进行处理
    private String handle(String request){
        return request;
    }

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

UDP回显客户端的代码

java">package UdpEcho;

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: wuyulin
 * Date: 2023-08-09
 * Time: 11:53
 */
//UPD回显客户端
public class UdpEchoClient {
    private DatagramSocket socket=null;
    private String ipServer=null;   //用来存储用户提供的服务器ip地址
    private int portSever=0;    //用来存储用户提供的服务器端口号

    //在实例化客户端的时候需要用户提供服务器的ip地址和端口号,这样才知道该客户端要联系哪个服务器
    public UdpEchoClient(String ipServer,int portSever) throws SocketException {
        this.ipServer=ipServer;
        this.portSever=portSever;
        //因为客户端的端口号是有操作系统随机分配的,要是指定客户端的端口号可能会导致冲突
        //所以实例化DatagramSocket对象的时候不写参数,不指定端口号
        socket=new DatagramSocket();
    }

    //开启客户端
    public void start() throws IOException {
        Scanner scanner=new Scanner(System.in);
        System.out.println("客户端启动");
        //要不停的读取用户输入的请求,将请求发送给服务器,并接收服务器发送回来的响应
        while (true){
            System.out.print("请求->");
            String request=scanner.next();

            //根据用户输入的请求实例化DatagramPacket数据报(因为UDP类型网络编程数据传输的基本单位是DatagramPacket数据报)
            //由于要将客户端的请求发送给服务器,所以需要在DatagramPacket类中声明服务器的ip地址和端口号
            //通过InetAddress类调用静态方法getByName实例化InetAddress类型的对象,getByName方法可以叫做工厂方法
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(ipServer),portSever);
            //将用户的请求发送给客户端
            socket.send(requestPacket);

            //接收服务器返回的的回应
            DatagramPacket reposePacket=new DatagramPacket(new byte[4080],4080);
            socket.receive(reposePacket);
            //对回应的数据报进行解析
            String repose=new String(reposePacket.getData(),0,reposePacket.getLength());
            //输出解析后得到的回应
            System.out.println(repose);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient udpEchoClient=new UdpEchoClient("127.0.0.1",8080);
        udpEchoClient.start();
    }
}

当我们用idea实现了上面的代码后可以通过idea如何开启多个客户端(一个代码开启多个客户端运行)来检验多个客户端向服务器传送请求的运行情况


http://www.niftyadmin.cn/n/4925547.html

相关文章

vue+Highcharts绘制3D饼图

效果图 一、下载highcharts插件 npm install highcharts 二、main.js全局配置插件 import Highcharts from "highcharts/highcharts"; import highcharts3d from "highcharts/highcharts-3d"; highcharts3d(Highcharts); 三、封装highcharts.vue组件 …

《Vue.js实战》——基础篇(1)

目录 资源:🌟 一、初识Vue.js👋 Vue.js是什么?🙇 MVVM模式 ✍ Vue.js有什么不同 ☔ 如何使用Vue.js? ☁ 传统的前端开发模式 ☀ Vue.js的开发模式 🗻 二、数据绑定和第一个Vue应用 &#x1f5f…

Vscode无法写入文件 NoPermissions (FileSystemError): Error: EACCES: permission

用Vscode想要新建一个index.html的时候遇到了下图问题,说没有权限无法写入文件。 没有权限,咱们给他加上权限哈哈哈,博主是Mac电脑,如下操作: 1.找到你项目的根目录,右键,点击“显示简介”。 …

南大通用数据库-Gbase-8a-学习-37-delete误删数据恢复方法

一、前提 在delete误删数据之后,没有再对此表进行其他ddl、dml和load等操作,可以使用手动切换AB版本的方式来进行数据恢复。 二、环境 名称值CPUIntel(R) Core(TM) i5-1035G1 CPU 1.00GHz操作系统CentOS Linux release 7.9.2009 (Core)内存3G逻辑核数…

postgresql|数据库|角色(用户)管理工作---授权和去权以及usage和select两种权限的区别

前言: postgresql做为一个比较复杂的关系型的重型数据库,不管是安装部署,还是后期的运行维护,都还是有比较多的细节问题需要引起关注。 例如,用户权限的合理分配,那么,什么是权限的合理分配呢…

预测成真,国内传来三个消息,中国年轻人变了,创新力产品崛起

中国的年轻人真的变了! 最近,国内传来三个消息,让外媒的预测成真。 第一,奥迪要开始用国产车的平台了。这里需要说明的是新能源汽车,奥迪也曾多次公开表示,承认了当前中国新能源汽车核心技术上的领先。 第…

Salesforce 助理认证和管理员认证有何区别?备考者应如何选择?

随着Salesforce生态系统对专业人员的需求不断增长,获得相关认证对于寻求职业发展的从业者来说至关重要。 对于刚接触Salesforce平台的人而言,Salesforce助理认证和Salesforce管理员认证是两个比较基础的认证。这两个认证有什么区别呢?从业者…

【LeetCode 算法】Subtract the Product and Sum of Digits of an Integer 整数的各位积和之差

文章目录 Subtract the Product and Sum of Digits of an Integer 整数的各位积和之差问题描述:分析代码Math Tag Subtract the Product and Sum of Digits of an Integer 整数的各位积和之差 问题描述: 给你一个整数 n,请你帮忙计算并返回…