【JavaEE】——Udp翻译器的实现(回显服务器)

简介: 网络编程,DatagramSocket 和 DatagramPacket类,回显服务器,服务器实现,客户端实现,

  image.gif 编辑

阿华代码,不是逆风,就是我疯

你们的点赞收藏是我前进最大的动力!!

希望本文内容能够帮助到你!!

目录

一:引入

1:基本概念

二:UDP socket API使用

1:socket文件

2:DatagramSocket类

(1)构造方法

(2)方法

3:DatagramPacket类

三:回显服务器——服务器

1:引入(必看)

2:服务器响应代码

(1)注释版本

(2)无注释版本

3:细节补充

4:特点

四:回显服务器——客户端

1:代码

(1)注释版本

(2)无注释版本

2:注意点

五:回显服务器过程文字梳理

六:知识补充


前引:本文代码建议反复敲打至少3遍!!!!

一:引入

1:网络编程的基本概念

网络编程就是通过写代码来完成基于网络的跨主机通信

本质上是学习传输层给应用层提供的一系列的API,通过API把数据交给传输层,在经过层层封装之后,通过网卡,把数据发送出去。

这里使用的API是传输层提供的,传输层涉及到的主要协议有两个:TCP和UDP

后面通过代码详细理解这些特点

image.gif 编辑

①有/无连接:这里的“连接”是虚拟的,抽象的连接

例:打电话——打过去对方接才能通话;微信发消息不管对面在不在线,消息都发出去了

②可/不可靠传输:可以知道数据到没到达对方

③面向字节流:传输数据的基本单位就是字节

④面向数据报:传输的的基本单位是一个“数据报”——由一系列字节构成的特定结构UDP

⑤全双工:可以双向通信

⑥半双工:只能单向通信

客户端:发送请求的一方,发送的数据叫做“请求”

服务器:被动接受请求的一方,给客户端返回的数据叫做“响应”

客户端和服务器之间的交互有这几种模式:“一问一答”,“一问多答”,“多问一答”,“多问多答”,

二:UDP socket API使用

引入:UDP核心类有两个DatagramSocket,DatagramPacket

1:socket文件

操作系统中有一类文件就叫做socket文件,区别于放在硬盘上的普通文件,socket文件是放在“网卡”这样的硬件设备上——通过网卡发送数据,就是写socket文件;接受数据,就是读socket文件

2:DatagramSocket类

(1)构造方法

image.gif 编辑

(2)方法

image.gif 编辑

3:DatagramPacket类

UDP面向数据报,每次发送和接收数据的基本单位就是一个UDP数据报

(1)构造方法

image.gif 编辑

下面这个图建议读完代码后再进行理解

image.gif 编辑

(2)方法

image.gif 编辑

三:回显服务器——服务器

1:引入(必看)

以下代码是实现一个“回显服务器”——是网络编程中的“hello world”,但是对新手小白并不友好

大致流程为:客户端发出请求,服务器收到客户端的请求,完成业务并返回响应,客户端接受响应

先附赠上服务器的代码,(按照步骤去边理解边敲)(重在理解,重在理解)

2:服务器响应代码

(1)注释版本

package network;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Hua YY
 * Date: 2024-10-07
 * Time: 17:20
 */
public class UdpEchoServer {
    //1:创建DatagramSocket对象
    private DatagramSocket socket = null;//socket:插槽插座
    //2:构造方法,服务器一启动,就要关联/绑定上一个操作系统中的端口号(服务器的端口号哦啊通常由程序员指定)
    //抛出的异常通常为scoket创建失败
    public UdpEchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);//端口号port
    }
    //3:服务器启动逻辑
    //5:抛异常,网络编程socket本质上也是IO
    public void start() throws IOException {
        System.out.println("服务器启动");
        while(true){
            //3:创建一个数据报,它是每次发送数据和接收数据的一个基本单位
            // 参数为输出型参数,字节数组,对应UDP的载荷部分,一开始是空的
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            //4;socket读网卡能读到一个UDP数据报(里面会包含数据源IP,源端口),放到requestPacket(数据报)对象中
            //如果没有接受到请求那么就会阻塞等待,此处收到的数据是先存到socket文件的内存缓冲区中。非硬盘
            socket.receive(requestPacket);
            //5:基于字节数组构造String对象,数组中的数据可能是文本数据(给String刚好)也可能是二进制数据(Java也能保存)
            //这里的长度是有效长度
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            //6:根据请求计算响应
            String response = process(request);
            //7:把响应(String)字节给拎出来,构造成一个DatagramPacket数据报,在传入socket对象(因为4中我们说过收到请求时,socket能读到源IP和源端口)
            //这时我们把这个源IP和源端口,作为响应的目的IP和目的端口(确认客户端的发出请求的位置),返回回去
            //注:response.length()单位是字符,此处单位是字节
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes() , response.getBytes().length , requestPacket.getSocketAddress());
            socket.send(responsePacket);
        }
    }
    //7:构造响应,这里是回显服务器,所以就是单纯的return
    private String process(String request) {
        return request;
    }
}

image.gif

(2)无注释版本

package repeat2;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Hua YY
 * Date: 2024-10-10
 * Time: 18:28
 */
public class UdpServer {
    private DatagramSocket socket = null;
    public UdpServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }
    public void start() throws IOException {
        System.out.println("服务器启动");
        while(true){
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPacket);
            //转化为字符串
            String request = new String(requestPacket.getData(),0,requestPacket.getLength());
            String response = process(request);
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s,%d]  request: %s  response: %s\n ",
                    requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);
        }
    }
    public String process(String request){
        return request;
    }
    public static void main(String[] args) throws IOException {
        UdpServer server = new UdpServer(9096);
        server.start();
    }
}

image.gif

3:细节补充

这里在补充一些细节:

①创建完socket对象后,可以通过socket对象来操作网卡(具体:因为socket对象是在内存中的,针对这个内存对象进行操作就可以影响到网卡)

②构造方法(还有无参的上面有写)中的参数,是我们指定的,进程一启动就要绑定上操作系统中的端口号,这个端口号是一个整数,用来区分一个主机上的进行网络通信的不同程序

一个端口号只能被一个进程绑定,但是一个进程可以绑定多个端口号(像极了爱情~~,爱情中宁死不做端口号~~)

image.gif 编辑

③SocketException,类似端口号被别的进程占用就会报异常

④因为服务器需要不停的运作,所以while一直循环

⑤数据报中的数组就是载荷部分

image.gif 编辑

⑥receive有阻塞等待功能

image.gif 编辑

⑧数据报的位置在socket对象的内存缓冲区中

image.gif 编辑

⑨构造响应数据报

4:特点

上述代码可以体现出UDP是——

(1)无连接通信

UDP的DAtagramSocket自身并不需要保存对端的IP和端口,对端IP和端口在数据报中就已经包含,另外代码中也没有“建立连接”和“接受连接”这种操作

(2)不可靠数据——代码没体现(略)

(3)面向数据报

send方法和receive方法都是以DatagramPacket为基本单位的

(4)全双工

一个socket既可以发送数据报又可以接受数据报(属于是自力更生了)

四:回显服务器——客户端

1:代码

(1)注释版本

package network;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Hua YY
 * Date: 2024-10-07
 * Time: 17:20
 */
public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;
    public UdpEchoClient(String serverIp , int serverPort) throws SocketException {
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        socket = new DatagramSocket();//传入参数为请求的目的ip和目的端口,源ip为本机ip源端口为系统分配的端口
    }
    public void start() throws IOException {
        System.out.println("客户端启动");
        Scanner scanner = new Scanner(System.in);
        while(true){
            System.out.print("->");
            if (!scanner.hasNext()){//如果没有输入的话就结束循环
                break;
            }
            String request = scanner.next();//人为输入请求
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);//指定服务器的ip和端口,分开的
            socket.send(requestPacket);
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096] , 4096);
            socket.receive(responsePacket);
            //转化为字符串
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());//内置getLength()获取length成员变量
            System.out.println(response);
        }
    }
    public static void main(String[] args) throws IOException {
        UdpEchoClient client = new UdpEchoClient("127.0.0.1",9090);
        client.start();
    }
}

image.gif

(2)无注释版本

package repeat2;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: Hua YY
 * Date: 2024-10-10
 * Time: 18:29
 */
public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIp;
    private int serverPort;
    public UdpEchoClient(String serverIp , int serverPort) throws SocketException {
        this.serverIp = serverIp;
        this.serverPort = serverPort;
        socket = new DatagramSocket();
    }
    public void start() throws IOException {
        System.out.println("客户端启动");
        Scanner scanner = new Scanner(System.in);
        while(true){
            System.out.print("->");
            if(!scanner.hasNext()){
                break;
            }
            String request = scanner.next();
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),
                    request.getBytes().length, InetAddress.getByName(serverIp),serverPort);
            socket.send(requestPacket);
            //接收响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096] , 4096);
            socket.receive(responsePacket);
            String response = new String(responsePacket.getData(),0,responsePacket.getLength());
            System.out.println(response);//
        }
    }
    public static void main(String[] args) throws IOException {
        UdpEchoClient client = new UdpEchoClient("127.0.0.1",9096);
        client.start();
    }
}

image.gif

2:注意点

(1)服务器端口号需要手动指定,是确保客户端可以找到服务器,客户端的端口号是操作系统的内核随机分配的 (确保分配的端口号是空闲可用的)

(2)Scanner从控制台读取字符串最好使用next非nextLine

(如果是从文件读取就无所谓了)

①next读取

image.gif 编辑

image.gif 编辑

②nextLine读取

image.gif 编辑 image.gif 编辑

(3).length和.length()方法的区别

image.gif 编辑

image.gif 编辑

五:回显服务器过程文字梳理

image.gif 编辑

六:知识补充

1:.length和.length()的区别

引用文章java中length和length()的区别_length变量与length函数 java-CSDN博客

image.gif 编辑

2:字符串转数组

image.gif 编辑

image.gif 编辑

七:易错的地方

构造String用getData(),有0-多少范围,

构造DatagramPacket用getBytes(),范围为getBytes().length

服务器获取客户端地址用:.getSocketAddress()

客户端获取服务器地址用:InetAddress.getByName(),serverPort

image.gif 编辑

image.gif 编辑

image.gif 编辑 image.gif 编辑 image.gif 编辑

相关文章
|
2月前
|
缓存 网络协议 Java
【JavaEE】——TCP回显服务器(万字长文超详细)
ServerSocket类,Socket类,PrintWriter缓冲区问题,Socket文件释放问题,多线程问题
|
2月前
|
XML JSON 算法
【JavaEE】——自定义协议方案、UDP协议
自定义协议,序列化,xml方案,json方案,protobuffer方案,UDP协议,校验和,比特翻转,CRC算法,md5算法
|
4月前
|
存储 网络协议 Java
【网络】UDP回显服务器和客户端的构造,以及连接流程
【网络】UDP回显服务器和客户端的构造,以及连接流程
84 3
|
4月前
|
网络协议 Java API
【网络】TCP回显服务器和客户端的构造,以及相关bug解决方法
【网络】TCP回显服务器和客户端的构造,以及相关bug解决方法
90 2
|
1天前
|
存储 机器学习/深度学习 人工智能
2025年阿里云GPU服务器租用价格、选型策略与应用场景详解
随着AI与高性能计算需求的增长,阿里云提供了多种GPU实例,如NVIDIA V100、A10、T4等,适配不同场景。2025年重点实例中,V100实例GN6v单月3830元起,适合大规模训练;A10实例GN7i单月3213.99元起,适用于混合负载。计费模式有按量付费和包年包月,后者成本更低。针对AI训练、图形渲染及轻量级推理等场景,推荐不同配置以优化成本和性能。阿里云还提供抢占式实例、ESSD云盘等资源优化策略,支持eRDMA网络加速和倚天ARM架构,助力企业在2025年实现智能计算的效率与成本最优平衡。 (该简介为原文内容的高度概括,符合要求的字符限制。)
|
2天前
|
存储 弹性计算 人工智能
2025年阿里云企业云服务器ECS选购与配置全攻略
本文介绍了阿里云服务器的核心配置选择方法论,涵盖算力需求分析、网络与存储设计、地域部署策略三大维度。针对不同业务场景,如初创企业官网和AI模型训练平台,提供了具体配置方案。同时,详细讲解了购买操作指南及长期运维优化建议,帮助用户快速实现业务上云并确保高效运行。访问阿里云官方资源聚合平台可获取更多最新产品动态和技术支持。
|
5天前
|
弹性计算 JavaScript 前端开发
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
Node.js 是一种高效的 JavaScript 运行环境,基于 Chrome V8 引擎,支持在服务器端运行 JavaScript 代码。本文介绍如何在阿里云上一键部署 Node.js 环境,无需繁琐配置,轻松上手。前提条件包括 ECS 实例运行中且操作系统为 CentOS、Ubuntu 等。功能特点为一键安装和稳定性好,支持常用 LTS 版本。安装步骤简单:登录阿里云控制台,选择扩展程序管理页面,安装 Node.js 扩展,选择实例和版本,等待创建完成并验证安装成功。通过阿里云的公共扩展,初学者和经验丰富的开发者都能快速进入开发状态,开启高效开发之旅。
|
1月前
|
弹性计算 数据挖掘 应用服务中间件
阿里云轻量应用服务器68元与云服务器99元和199元区别及选择参考
目前阿里云有三款特惠云服务器,第一款轻量云服务器2核2G68元一年,第二款经济型云服务器2核2G3M带宽99元1年,第三款通用算力型2核4G5M带宽199元一年。有的新手用户并不是很清楚他们之间的区别,因此不知道如何选择。本文来介绍一下它们之间的区别以及选择参考。
513 87
|
7天前
|
弹性计算 JavaScript 前端开发
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
一键安装!阿里云新功能部署Nodejs环境到ECS竟然如此简单!
|
1天前
|
存储 人工智能 弹性计算
2025年阿里云企业高性能云服务器租用价格与选型详解
随着企业数字化转型,阿里云于2025年推出多款高性能云服务器实例,涵盖计算、通用和内存密集型场景。文章分析了企业选择云服务器的核心要点,包括明确业务需求(如计算密集型任务推荐计算型实例)、性能与架构升级(如第八代实例性能提升20%),以及第九代实例支持AI等高算力需求。同时提供了配置价格参考和成本优化策略,助力企业实现效率与成本的最优平衡。