实现回显服务器(基于UDP)

发布于:2025-06-15 ⋅ 阅读:(19) ⋅ 点赞:(0)

目录

一.回显服务器的基本概念

二.回显服务器的简单示意图

三.实现回显服务器(基于UDP)必须要知道的API 

1.DatagramSocket

2.DatagramPacket 

3.InetSocketAddress

4.二者区别 

1. 功能职责

2. 核心作用

3. 使用场景流程

四.实现服务器端的主要思路 

代码部分如下

实现服务器端的注意事项 

五.实现客户端的主要思路

实现客户端的注意事项 

六.完整代码 

运行测试结果 


一.回显服务器的基本概念

回显服务器(Echo)可以看成是网络编程中的"hello world",是学习网络编程的入门。简单介绍一下,回显服务器就是服务端收到什么,就给客户端发送什么。我会基于UDP来实现一个回显服务器。

二.回显服务器的简单示意图

三.实现回显服务器(基于UDP)必须要知道的API 

1.DatagramSocket

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

void receive(DatagramPacket p)

   

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

2.DatagramPacket 

方法签名 方法说明
DatagramPacket(byte[] buf, int length) 构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号
InetAddress getAddress() 从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort() 从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData() 获取数据报中的数据

3.InetSocketAddress

方法签名 方法说明
InetSocketAddress(InetAddress addr, int port) 创建一个 Socket 地址,包含 IP 地址和端口号

4.二者区别 

1. 功能职责

  • DatagramSocket:是套接字类,相当于 “码头”,负责发送、接收DatagramPacket数据报,还能绑定端口、管理网络连接(虽 UDP 无连接,但它提供收发的基础通道 ),比如通过send发送数据报、receive接收数据报,close关闭套接字。
  • DatagramPacket:是数据报类,相当于 “集装箱”,负责封装 UDP 通信中要发送或接收的数据,包含数据内容、数据长度,以及发送 / 接收时的目标地址(IP + 端口 )或源地址信息。

2. 核心作用

  • DatagramSocket聚焦网络收发操作,决定 “怎么传”(用哪个端口、怎么建立收发通道 );
  • DatagramPacket聚焦数据封装,决定 “传什么”(数据内容 )和 “传给谁 / 从哪收”(地址信息 ) 。

3. 使用场景流程

UDP 通信时,先创建DatagramSocket作为收发的 “通道”,再创建DatagramPacket封装数据 / 地址,最后通过DatagramSocketsend/receive完成数据收发 。比如客户端用DatagramSocket发送封装了数据和目标地址的DatagramPacket;服务器端用DatagramSocket绑定端口,接收包含数据和源地址的DatagramPacket 。

四.实现服务器端的主要思路 

1.读取请求并解析

2.根据请求,计算响应

3.把响应返回给客户端

4.打印日志(方便观察)

代码部分如下

public void start() throws IOException {
        while(true){
            //1.读取请求并解析
            DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
            //输出型参数
            socket.receive(requestPacket);
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            //2.根据请求,计算响应
            String response=process(request);
            //3.把响应返回给客户端
            DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            //4.打印日志
            System.out.printf("[%s:%d,request:%s response:%s]\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);
        }
    }

实现服务器端的注意事项 

五.实现客户端的主要思路

1.在控制台读取用户要输入的内容

2.把请求发送给服务器

3.发送请求数据包给服务器端

4.接收服务器端的响应

5.把从服务器读取的数据进行解析,打印出来

  public void start() throws IOException {
        Scanner scanner=new Scanner(System.in);
        while(true){
            System.out.println("请输入内容");
            //按ctrl+d会break
            if(!scanner.hasNext()){
                break;
            }
            //1。从控制台读取用户要输入的内容
            String resquest=scanner.next();
            //2.把请求发送给服务器
            DatagramPacket resquestPacket=new DatagramPacket(resquest.getBytes(),resquest.getBytes().length,InetAddress.getByName(ServerIp),
                    ServerPort);
//            socket.receive(resquestPacket);
            //3.发送请求数据包给服务器端
            socket.send(resquestPacket);
            //4.接收服务器端的响应
            DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            //5.把从服务器读取的数据进行解析,打印出来
            String response=new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);

        }
    }

实现客户端的注意事项 

六.完整代码 

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;

public class UdpEchoClient {
    private DatagramSocket socket=null;
    //记录ip与端口号
    private String ServerIp;
    private int ServerPort;
    //服务器的ip与端口号
    public UdpEchoClient(String ServerIp,int ServerPort) throws SocketException {
        this.ServerIp=ServerIp;
        this.ServerPort=ServerPort;
        //客户端这里的端口号等到操作系统随机分配
        socket=new DatagramSocket();
    }
    public void start() throws IOException {
        Scanner scanner=new Scanner(System.in);
        while(true){
            System.out.println("请输入内容");
            //按ctrl+d会break
            if(!scanner.hasNext()){
                break;
            }
            //1。从控制台读取用户要输入的内容
            String resquest=scanner.next();
            //2.把请求发送给服务器
            DatagramPacket resquestPacket=new DatagramPacket(resquest.getBytes(),resquest.getBytes().length,InetAddress.getByName(ServerIp),
                    ServerPort);
//            socket.receive(resquestPacket);
            //3.发送请求数据包给服务器端
            socket.send(resquestPacket);
            //4.接收服务器端的响应
            DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
            socket.receive(responsePacket);
            //5.把从服务器读取的数据进行解析,打印出来
            String response=new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);

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


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

public class UdpEchoServer {
    private DatagramSocket socket=null;
    public UdpEchoServer(int port) throws SocketException {
        socket=new DatagramSocket(port);
    }
    public void start() throws IOException {
        while(true){
            //1.读取请求并解析
            DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);
            //输出型参数
            socket.receive(requestPacket);
            String request=new String(requestPacket.getData(),0,requestPacket.getLength());
            //2.根据请求,计算响应
            String response=process(request);
            //3.把响应返回给客户端
            DatagramPacket responsePacket=new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            //4.打印日志
            System.out.printf("[%s:%d,request:%s response:%s]\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);
        }
    }

    //将private改为public,方便方面有新功能,可以进行重写
    public String process(String request) {
        return request;
    }
    public static void main(String[] args) throws IOException {
        UdpEchoServer udpEchoServer=new UdpEchoServer(1777);
        udpEchoServer.start();

    }
}

运行测试结果