实现回显服务器(基于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封装数据 / 地址,最后通过DatagramSocket的send/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();

    }
}

运行测试结果

相关推荐
文丑颜不良啊10 分钟前
LeetCode276~300题目解析
java·leetcode
Vegetable_xu15 分钟前
Spring Bean 循环依赖:为什么有时能过、有时启动就挂
java·spring·mybatis
avi91111 小时前
【AI教人】在Inspector显示所有Delegate-Odin Inspector之三
java·前端·算法·delegate·inspector·editor扩展·unity editor
青春不朽5121 小时前
Python 的 list append 为什么是均摊 O(1)?拆开过度分配那张表,看容量翻倍背后的暗账
java·python·list
小羊没烦恼!2 小时前
.NET 11 Runtime Async 详解
java·运维·开发语言·javascript·python
哇嘎呀2 小时前
RHCSA题目
java·服务器·前端
SL_staff2 小时前
企业知识平台细粒度权限设计实践:从成员组、文档库到操作级的三层防线
java·开源·全栈
周厉2 小时前
ERP系统全景解析:核心模块与业务逻辑框架
java·服务器·前端
开开心心就好3 小时前
课堂随机点名工具,绿色版免安装双击即用
java·服务器·前端·ffmpeg·音视频·perl·symfony
code2cat3 小时前
Java高级篇之Socket:从建立连接到完整收发一条消息
java·开发语言