首页 > 编程语言 >【Javaee】网络编程-UDP基础

【Javaee】网络编程-UDP基础

时间:2024-10-21 15:52:26浏览次数:7  
标签:UDP DatagramPacket String request 编程 Javaee 服务器 new public

  前言

UDP是一个高效、快速、简单的传输协议,适合于需要低延迟和实时性的应用

本篇将介绍UDP相关的api,并使用UDP构建回显服务器程序。


一.UDP与TCP

特点

UDP:无连接,不可靠,面向数据报,全双工。

TCP:有连接,可靠,面向字节流,全双工。

何为连接

此处所说的连接是抽象的连接,并不是实际两根线的相连,是指通信双方是否保留对方的信息(如IP地址,端口号)。

UDP是无连接的,通信双方不会保留对方的地址。

TCP是有连接的,通信双方保留着对方的地址。

何为可靠?

可靠指的是通信双方是否关注信息正确的传递到对方手上,可靠指会尽可能的确保数据传输到对方,不可靠是不关心数据是否传输过去。 

UDP是不可靠的,指的是当通信出现问题时,会直接把数据包丢弃,不会进行重传。

TCP是可靠的,指通信出现问题时,有着应答响应延时重传机制,防止数据的丢失

面向数据报与面向字节流

两种协议的传输单位不同。

数据报是一种专门为网络通信传输构造的特殊结构的传输单位,将需要传输的数据打包成一个整体。

UDP协议传输时,以一整个数据报为单位进行传输。

TCP协议面向字节流指的是数据被视为一个连续的字节序列,发送 方将数据拆分为字节流发送,而接收方将这些字节流重新组装成原始数据

全双工与半双工

全双工:一个通信信道,可以双向通信(既可以发送数据,也可以同时接收数据)

半双工:只能单向通信(接收数据与发送数据不能同时发送)

二.UDP的常用api

对于UDP来说,主要提供了两个核心api,即DatagramSocketDatagramPacket(相当于网卡的遥控器)

1.DatagramSocket

1)构造方法

方法签名方法说明
DatagramSocket()

创建⼀个UDP数据报套接字的Socket,绑定到本机任意一个

随机端口(一般用于客户端)

DatagramSocket(int port)

创建⼀个UDP数据报套接字的Socket,绑定到本机指定的

端口(一般用于服务器)

2)DatagramSocket方法

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

2.DatagramPacket

1.构造方法

方法签名方法说明
DatagramPacket(byte[] buf, int length)构造⼀个DatagramPacket以⽤来接收数据报,接收的数据保存在字节数组(第⼀个参数buf)中,接收指定⻓度(第⼆个参数length)
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address)构造⼀个DatagramPacket以⽤来发送数据报,发送的 数据为字节数组(第⼀个参数buf)中,从0到指定⻓度(第⼆个参数length)。address指定⽬的主机的IP 和端⼝号

2.DatagramPacket方法

方法签名方法说明
InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端⼝号;或从发送的数据报中,获取接收端主机端⼝号
byte[] getData()获取数据报中的数据

当看方法,可能看的云里雾里,接下来通过代码来演示

三.UDP服务器端实现

1.代码实现

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

public class UdpService {
    private DatagramSocket socket = null;

    public UdpService(int port) throws SocketException {
        socket = new DatagramSocket(9090);
        //参数是服务器绑定的端口
    }

    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],服务器响应:%s,客户机请求:%s", requestPacket.getSocketAddress(),
                    response, request);
        }
    }

    public String process(String request) {
        return request;
        //回显服务器,返回请求,不做其他操作
    }

    public static void main(String[] args) throws IOException {
        UdpService service=new UdpService(9090);
        service.start();

    }
}

2.代码解析

服务器的基本流程主要分为3个部分

1)读取请求并解析

DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(requestPacket);
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());

此段代码中,首先定义requestPacket数据报,确定数据报的大小,再接收客户端请求,放入数据报中,并解析请求信息。

2)根据请求计算响应【服务器最重要的环节】

 String response = process(request);

 public String process(String request) {
        return request;
        //回显服务器,返回请求,不做其他操作
    }

此代码实现的为回显服务器,将请求作为响应返回,不涉及其他逻辑

3)把响应写回给客户端,打印日志

 DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s:%d],服务器响应:%s,客户机请求:%s", requestPacket.getSocketAddress(),
                    response, request);

定义responsePacket数据报,将response的信息打包好,定义好发送的ip地址和端口号,用send发送回客户端,并打印出客户端的ip 端口 请求信息和响应信息。

四.UDP客户端实现

1)代码实现

import java.io.IOException;
import java.net.*;
import java.util.Scanner;

public class UdpCilent {
   private DatagramSocket socket=null;
   private String ServiceIP;
   private int ServicePort;
   public UdpCilent(String serviceIP,int servicePort) throws SocketException {
       this.ServiceIP=serviceIP;
       this.ServicePort=servicePort;
       socket=new DatagramSocket();
   }
   public void start() throws IOException {
       System.out.println("客户端启动");
       Scanner scanner=new Scanner(System.in);
       while (true){
           System.out.println("->");
           String request= scanner.next();
           DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(this.ServiceIP),
                   this.ServicePort);
           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 {
        UdpCilent cilent=new UdpCilent("127.0.0.1",9090);
        cilent.start();
    }
}

2)代码解析

1)从控制台中输入指令,将指令打包成数据报,数据报中要指明服务器的ip地址和端口号,才能将数据发送给对应的服务器处理

public class UdpCilent {
   private DatagramSocket socket=null;
   private String ServiceIP;
   private int ServicePort;
   public UdpCilent(String serviceIP,int servicePort) throws SocketException {
       this.ServiceIP=serviceIP;
       this.ServicePort=servicePort;
       socket=new DatagramSocket();
   }
   public void start() throws IOException {
       System.out.println("客户端启动");
       Scanner scanner=new Scanner(System.in);
       while (true){
           System.out.println("->");
           String request= scanner.next();
           DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(this.ServiceIP),
                   this.ServicePort);
           socket.send(requestPacket);

2)定义响应数据报,接收服务器处理完数据后的响应,并打印出来。

 DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);
           socket.receive(responsePacket);
           String response=new String(responsePacket.getData(),0,responsePacket.getLength());
           System.out.println(response);

3)启动程序,在new 对象中填入服务器的ip与端口号。

 public static void main(String[] args) throws IOException {
        UdpCilent cilent=new UdpCilent("127.0.0.1",9090);
        cilent.start();
    }

五.服务器与客户端执行过程

1.执行流程

1)首先控制台输入指令,客户端发送请求到服务器。

2)紧接着,服务器接收到请求,解除阻塞

3)服务器把得到的数据构造成string,执行process()方法对数据进行操作,返回操作结果response,并打包成数据报发送会客户端

4)客户端收到了返回的响应后,解除阻塞

5)打印日志,进入下一次循环

2.字典服务器

字典服务器提供着将客户端输入的英文转化中文,只需继承UDP服务器,并重写proces方法即可实现。

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

public class DictService extends UdpService{
    private Map<String,String> dict=new HashMap<String,String>();
    public DictService(int port) throws SocketException {
        super(port);
        dict.put("cat","猫");
        dict.put("dog","狗");
        dict.put("duck","鸭子");
        dict.put("fish","鱼");
    }

    @Override
    public String process(String request) {
        return dict.getOrDefault(request,"未知单词");
    }

    public static void main(String[] args) throws IOException {
        DictService servicer=new DictService(9090);
        servicer.start();
    }


以上便是全部内容,如有不对,欢迎指正

标签:UDP,DatagramPacket,String,request,编程,Javaee,服务器,new,public
From: https://blog.csdn.net/yc_xym/article/details/143043164

相关文章

  • 高效并行计算:使用C++中的std::thread实现多线程编程
    解锁Python编程的无限可能:《奇妙的Python》带你漫游代码世界在现代计算中,随着多核处理器的普及,如何充分利用硬件资源以提升程序性能成为关键问题之一。C++标准库提供了丰富的多线程支持,其中std::thread是用于实现并发计算的核心工具之一。通过合理的多线程设计,程序可以实现......
  • 嵌入式※~CH395Q-UDP
    我自己的原文哦~ https://blog.51cto.com/whaosoft/11683296网络芯片CH395Q-模块使用Socket0作为UDP组播(多播)通信这里演示一下模块使用Socket0作为UDP组播(多播)通信提醒:无论是SPI,USART,并口,程序操作步骤都是一样的!只是不同的接口发指令发给模块,然后用不同的接收......
  • TCP和UDP的报文格式
    TCP和UDP的报文格式  概要 了解TCP和UDP的报文格式对于网络通信、系统设计、故障排查和安全性等多个方面都非常重要。 一、TCP报文格式(TransmissionControlProtocol) TCP是面向连接、可靠的传输协议,其报文格式较复杂。TCP报文的格式如下:  上图简化如下:|......
  • 少儿Scratch图形化编程案例100课——010美妙的图形
     ......
  • 少儿Scratch图形化编程案例100课——008制作动画电影
    ......
  • 【c++篇】:解析c++类--优化编程的关键所在(一)
    文章目录前言一.面向过程和面向对象二.c++中的类1.类的引入2.类的定义3.类的封装和访问限定符4.类的作用域5.类的实例化6.类对象模型三.`this`指针1.`this`指针的引出2.`this`指针的特性3.C语言和c++实现栈Stack的对比前言在程序设计的广袤宇宙中,C++以其强大的功能......
  • shell编程小技巧:进程替换
    今天来给大家介绍一个非常好用的shell编程技巧,即进程替换(Processsubstitution)。进程替换可以将一个进程(程序)的输入或输出当做一个文件来使用。它的两种使用形式为:<(cmd)或>(cmd).需要注意的是,<和>与(之间不能有空格!下面通过一个示例来介绍进程替换的具体用法。假如我有一个......
  • 10.18Python基础迭代器生成器_函数式编程
    Python迭代器与生成器1.迭代器Iterator什么是迭代器迭代器是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。迭代器可以重复使用,而不会像列表那样在迭代时被修改。迭代器函数iter和next函数说明iter(iterable)从可迭代对象中返回一个迭代器,iterabl......
  • 事务 - 编程式事务
    packagecom.example.demo.service;importcom.example.demo.mapper.UserMapper;importcom.example.demo.model.User;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.tran......
  • C系统编程通信方式——共享内存
        共享内存,标准IPC之一,也是进程间通信最快的一种方式。1.概念    所有的标准IPC都有一个内部ID作为唯一标识。内部ID的获取通过外部key,key的类型是key_t。key的获取方法有在头文件中定义所有key和通过ftok函数获取一个key。key_tftok(constchar*pathna......