当前位置: 首页 > article >正文

网络编程套接字之UDP

目录

一、网络编程

二、UDP数据报套接字编程

DatagramSocket

DatagramPacket

实现客户端服务器程序

UDPchoServer


一、网络编程

我们网络编程的核心: Socket API,操作系统为我们应用程序提供的API,我们的Socket是和传输层密切相关的。

我们传输层为我们提供了两个最核心的协议UDP/TCP,所以我们的Socket API也为我们提供了TCP/UDP。
简单认识一下TCP/UDP:
TCP 有连接 可靠传输 面向字节流 全双工
UDP 无连接 不可靠传输 面向数据报 全双工

TCP:
特点:

  1. 使用TCP协议,必须双方先建立连接,它是一种面向连接的可靠通信协议
  2. 传输前,采用”三次握手"方式建立连接,所以是可靠的
  3. 在连接中可进行大数据量的传输
  4. 连接、发送数据都需要确认,且传输完毕后,还需释放已建立的连接,通信效率低

应用场景:对信息安全要求较高的场景,例如:文件下载、金融等数据通信

UDP
特点:

UDP是一种无连接,不可靠传输协议
将源IP、目的IP和端口封装成数据包,不需要建立连接
每个数据包大小限制在64kb内
发送不管对方是否准备好,接收方收到也不确认,所以是不可靠的
可以广播发送,发送数据结束时无需释放资源,开销小,速度快
应用场景: 语音通话,视频会话等

二、UDP数据报套接字编程

DatagramSocket

DatagramSocket 这个类表示一个Socket对象,我们操作系统中,把socket对象是当作一个文件来处理的。
一个Socket对象就可以与另一台主机进行通信了,如果要和不同的主机通信,就需要创建多个Socket对象

方法作用
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到任意一个随机端口号(一般用于客户端)
DatagramSocket(int port)创建一个UDP数据报套接字的Socket,绑定到本机指定端口(一般用于服务器)
方法作用
void receive(DatagramPacket p)从此套接字接收数据,如果没有接收到数据报,进行阻塞等待)
void send(DatagramPacket p)从此套接字发送数据包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

我们的receive方法参数传入的是一个空的对象,receive方法内部会对这个对象进行填充,从而构造出结果数据,我们称这样的参数为输出型参数

DatagramPacket

DatagramPacket是UDP socket进行发送和接收的数据报。

方法作用
DatagramPacket(byte[] buf,int length)构造一个DatagramPacket用来接收数据报,接收的数据保存在字节数组里,接受指定长度
DatagramPacket(byte[] buf,int offset,int length,SocketAddress address)构造一个DatagramPacket用来发送数据报,发送的数据为字节数据,从0到指定长度,address用来指定目的主机的IP和端口号

DatagramPacket的一些方法:

方法作用
InetAddress getAddress()从接受的数据报中,获取发送端IP地址,或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号,或从发送的数据报中,获取接收端的端口号
byte[] getData()获取数据报的数据

实现客户端服务器程序

我们在这里编写一个最简单的客户端服务器程序:回显服务器(echo server).
我们的服务器做的工作:收到请求,根据请求计算响应,返回响应,最重要的环节就是计算响应这一部分,我们的echo server省略了这一部分,接收到什么就返回什么。

UDPchoServer
//udp回显服务器
public class UDPchoServer {
    //声明一个提供udp服务的对象
    private DatagramSocket socket;
    // 通过构造方法指定服务器端口号
    public UDPchoServer(int port) throws SocketException {
        // 校验端口号
        if (port < 1024 || port > 65535) {
            throw new BindException("端口号建议在1024——65535之间");
        }
        //初始化udp服务端对象
        this.socket=new DatagramSocket(port);
    }

    //启动服务,处理用户表请求
    public void start() throws IOException {
        System.out.println("服务器已启动");
        //循环处理用户请求
        //每循环一次就表示处理了一个用户的请求,工作时间是7*24小时不间断
        while (true) {
            //1.使用DatagramPacket来接受用户发来的数据
            DatagramPacket requestpacket=new DatagramPacket(new byte[1024],1024);
            //2.接收数据
            socket.receive(requestpacket);
            //3.解析得到的数据,获取数据报内容
            String request = new String(requestpacket.getData(), 0, requestpacket.getLength(), "UTF-8");
            //4.通过请求计算响应
            String response=process(request);

            //5.定义一个用于响应的DatagramPacket封装响应的数据
            DatagramPacket responsePacket=new DatagramPacket(response.getBytes(StandardCharsets.UTF_8),0,response.getBytes().length
            ,requestpacket.getSocketAddress());

            //6.发送响应
            socket.send(responsePacket);
            //7.打印日志
            System.out.printf("[%s:%d] request = %s, response = %s\n",requestpacket.getAddress().toString(),requestpacket.getPort()
            ,request,response);
        }
    }

    protected String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        UDPchoServer udPchoServer = new UDPchoServer(8888);
        udPchoServer.start();

    }
}

UDPchoClient

//基于UDP的客户端
public class UDPchoClient {
    //声明一个DatagramSocket对象
    private DatagramSocket socket;
    //声明服务器id
    private String serverIp;
    //声明服务器端口号
    private int serverPort;

    public UDPchoClient(String serverId,int serverPort) throws SocketException {
        //初始化DatagramSocket对象
        this.socket=new DatagramSocket();
        this.serverIp=serverId;
        this.serverPort=serverPort;
    }

    public void start() throws IOException {
        System.out.println("客服端已启动");
        //循环处理客户端的输入
        while (true) {
            System.out.println("->");
            //定义Scanner
            Scanner scanner=new Scanner(System.in);
            //1.获取用户的输入
            String request=scanner.nextLine();
            if(request==null||request.isEmpty()){
                System.out.println("不能输入空字符串");
                continue;
            }
            SocketAddress address=new InetSocketAddress(serverIp,serverPort);
            //用DatagramPacket包装用户请求数据
            DatagramPacket requestPacket=new DatagramPacket(request.getBytes(StandardCharsets.UTF_8),0,request.getBytes().length,
                    address);
            //发送真实的数据到服务器
            socket.send(requestPacket);
            //接收服务器的响应
            DatagramPacket responsePacket=new DatagramPacket(new byte[1024],1024);
            //接受数据
            socket.receive(responsePacket);
            //解析数据得到响应
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength(), "UTF-8");
            System.out.printf("request=%s,response=%s\n",request,response);
        }
    }

    public static void main(String[] args) throws IOException {
        UDPchoClient client=new UDPchoClient("127.0.0.1",8888);
        client.start();
    }
}

http://www.kler.cn/a/554967.html

相关文章:

  • ArcGIS Pro制作人口三维地图教程
  • Linux初体验:从零开始掌握操作系统的发展与多样性
  • Ubuntu安装PostgreSQL
  • Webpack 基础入门
  • <iframe>标签嵌入pdf文件在谷歌浏览器中无法显示
  • ZLMediaKit Windows 编译指南
  • linux 搭建nfs服务(共享文件夹)
  • 从Majorana 1芯片看微软量子计算路径及竞品对比分析
  • android怎么卸载系统应用
  • 强化学习笔记之引论
  • 【数据分析】3 数据分析成长之路
  • three.js之特殊材质效果
  • VMware虚拟机打不开Ubuntu22.04,是否从库中移出Ubuntu_22.04_bak_1 64位.vmx 解决方法
  • Unity面板介绍_Project工程面板(23.1.1)
  • 深度学习在医疗影像分析中的革命性应用
  • [DeepSeek]一、DeepSeek+Dify创建工作流
  • python-leetcode 39.二叉树的直径
  • HTTP常见状态码和HTTP的发展
  • PLC数据采集网关(三格电子)
  • DeepSeek学习