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

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

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

UDP回显服务器代码

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回显客户端的代码

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如何开启多个客户端(一个代码开启多个客户端运行)来检验多个客户端向服务器传送请求的运行情况

你可能感兴趣的:(udp,服务器,网络协议,java)