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

目录

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

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

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

1.DatagramSocket

2.DatagramPacket

3.InetSocketAddress

4.二者区别

[1. 功能职责](#1. 功能职责)

[2. 核心作用](#2. 核心作用)

[3. 使用场景流程](#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.打印日志(方便观察)

代码部分如下

java 复制代码
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.把从服务器读取的数据进行解析,打印出来

java 复制代码
  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);

        }
    }

实现客户端的注意事项

六.完整代码

java 复制代码
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();


    }
}
java 复制代码
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();

    }
}

运行测试结果

相关推荐
电商数据girl30 分钟前
【经验分享】浅谈京东商品SKU接口的技术实现原理
java·开发语言·前端·数据库·经验分享·eclipse·json
小猫咪怎么会有坏心思呢1 小时前
华为OD机考-货币单位换算-字符串(JAVA 2025B卷)
java·开发语言·华为od
一坨阿亮2 小时前
MyBatis原理
java·开发语言·mybatis
不太可爱的叶某人3 小时前
【学习笔记】深入理解Java虚拟机学习笔记——第7章 虚拟机类加载机制
java·笔记·学习
CUIYD_19893 小时前
Spring MVC 处理静态资源请求 - ResourceHandler
java·spring·mvc
晴空月明4 小时前
Java 集合框架底层数据结构实现深度解析
java
louisgeek4 小时前
Java Creational 创建型模式之 Builder 建造者模式
java
挑战者6668884 小时前
springboot入门之路(一)
java·spring boot·后端
重整旗鼓~5 小时前
7.索引库操作
java·开发语言
云心雨禅5 小时前
Spring Boot热更新技巧:节省90%重启时间
java·数据库·spring boot