【JavaEE】网络编程---UDP数据报套接字编程

news/2024/5/18 13:01:36 标签: java-ee, udp, java, 1024程序员节

一、UDP数据报套接字编程

1.1 DatagramSocket API

DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。

DatagramSocket 构造方法:
在这里插入图片描述
DatagramSocket 方法:
在这里插入图片描述

1.2 DatagramPacket API

DatagramPacket是UDP Socket发送和接收的数据报。
DatagramPacket 构造方法:

在这里插入图片描述DatagramPacket 方法:
在这里插入图片描述

构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。

1.3 InetSocketAddress API

InetSocketAddress ( SocketAddress 的子类 )构造方法:
在这里插入图片描述

1.4 示例一:回显服务器(echo server)

客户端发了一个请求,服务器返回一个一模一样的响应

一个服务器的工作:
1、读取请求并解析
2、根据请求计算响应
3、把响应返回到客户端

1.4.1 UDP服务器

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

public class UdpEchoServer {
    // 需要先定义一个 socket 对象.
    private DatagramSocket socket = null;
    // 绑定一个端口, 不一定能成功!!
    // 如果某个端口已经被别的进程占用了, 此时这里的绑定操作就会出错.
    // 同一个主机上, 一个端口, 同一时刻, 只能被一个进程绑定.
    public UdpEchoServer(int port) throws SocketException {
        // 构造 socket 的同时, 指定要关联/绑定的端口.
        socket = new DatagramSocket(port);
    }
    // 启动服务器的主逻辑.
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while (true) {
            // 每次循环, 要做三件事情:
            // 1. 读取请求并解析
            //    构造空饭盒
            DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);
            //    食堂大妈给饭盒里盛饭. (饭从网卡上来的)
            socket.receive(requestPacket);
            //    为了方便处理这个请求, 把数据包转成 String
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
            // 2. 根据请求计算响应(此处省略这个步骤)
            String response = process(request);
            // 3. 把响应结果写回到客户端
            //    根据 response 字符串, 构造一个 DatagramPacket .
            //    和请求 packet 不同, 此处构造响应的时候, 需要指定这个包要发给谁.
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,
                    // requestPacket 是从客户端这里收来的. getSocketAddress 就会得到客户端的 ip 和 端口
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s:%d] req: %s, resp: %s\n", requestPacket.getAddress().toString(),
                    requestPacket.getPort(), request, response);
        }
    }

    // 这个方法希望是根据请求计算响应.
    // 由于咱们写的是个 回显 程序. 请求是啥, 响应就是啥
    // 如果后续写个别的服务器, 不再回显了, 而是有具体的业务了, 就可以修改 process 方法,
    // 根据需要来重新构造响应.
    public String process(String request) {
        return request;
    }

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

1.4.2 UDP客户端

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

public class UdpEchoClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;

    // 客户端启动, 需要知道服务器在哪里!!
    public UdpEchoClient(String serverIP, int serverPort) throws SocketException {
        // 对于客户端来说, 不需要显示关联端口.
        // 不代表没有端口, 而是系统自动分配了个空闲的端口.
        socket = new DatagramSocket();
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }

    public void start() throws IOException {
        // 通过这个客户端可以多次和服务器进行交互.
        Scanner scanner = new Scanner(System.in);
        while (true) {
            // 1. 先从控制台, 读取一个字符串过来
            //    先打印一个提示符, 提示用户要输入内容
            System.out.print("-> ");
            String request = scanner.next();
            // 2. 把字符串构造成 UDP packet, 并进行发送.
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
                    InetAddress.getByName(serverIP), serverPort);
            socket.send(requestPacket);
            // 3. 客户端尝试读取服务器返回的响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);
            socket.receive(responsePacket);
            // 4. 把响应数据转换成 String 显示出来.
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            System.out.printf("req: %s, resp: %s\n", request, response);
        }
    }

    public static void main(String[] args) throws IOException {
        UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1", 9090);
        // UdpEchoClient udpEchoClient = new UdpEchoClient("192.168.56.1", 9090);
        udpEchoClient.start();
    }
}

客户端发了一个请求,服务器返回一个一模一样的响应
在这里插入图片描述

1.5 示例二:翻译软件

继承示例一的服务器代码:

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

// 使用继承, 是为了复用之前的代码.
public class UdpDictServer extends UdpEchoServer {
    private Map<String, String> dict = new HashMap<>();

    public UdpDictServer(int port) throws SocketException {
        super(port);

        dict.put("dog", "小狗");
        dict.put("cat", "小猫");
        dict.put("fuck", "卧槽");
        // ........... 可以无限的添加很多很多数据. 有道词典和咱们相比, 就是人家的这个表更大!!
    }

    @Override
    public String process(String request) {
        return dict.getOrDefault(request, "该单词没有查到!");
    }

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

启动:
在这里插入图片描述
在这里插入图片描述
结果:
在这里插入图片描述


http://www.niftyadmin.cn/n/5117218.html

相关文章

使用 Requests 库和 PHP 的下载

以下是一个使用 Requests 库和 PHP 的下载器程序&#xff0c;用于从 www.people.com.cn 下载音频。此程序使用了 https://www.duoip.cn/get_proxy 这段代码。 import requests from bs4 import BeautifulSoup import pafy import timedef get_proxy():url "https://www.…

vue2中,下拉框多选和全选的实现

vue2中&#xff0c;下拉框多选和全选的实现 代码布局在methods: 中添加功能函数较为完整的一个整体代码&#xff1a; 如图所示点击全选即可完成下拉框中全部子项的全部的选中&#xff0c;同时取消全选即可全部取消选择。 代码布局 <div class"chos-box2"><…

Windows下 MySql 5.7授权远程登陆

1.用管理员身份打开mysql Client 2.输入密码登录 3.使用mysql数据库&#xff0c;输入“use mysql” 4.查看当前服务中使用的用户 select host,user form user; 5.授权 grant all privileges on *.* to 用户名% identified by 密码 with grant option; 6.成功后&#xff0c;刷…

【C语言】void类型和void*指针类型

【C/C】如何理解void*与int之间的类型转换--以pthread_create为例_void *转int-CSDN博客 【C语言】void 和 void* 类型_void*类型_yuelinghou的博客-CSDN博客 c语言中void和void*类型_system.void不能用作类型参数-CSDN博客 【C语言】void类型和void*指针类型_指尖动听知…

如何将音频与视频分离

您一定经历过这样的情况&#xff1a;当你非常喜欢视频中的背景音乐时&#xff0c;希望将音频从视频中分离出来&#xff0c;以便你可以在音乐播放器中收听音乐。有没有一种有效的方法可以帮助您快速从视频中提取音频呢&#xff1f;当然是有的啦&#xff0c;在下面的文章中&#…

eBay限制要求有哪些?如何提升产品权重:掌握自养号测评技巧

eBay针对不同类别的商品设定了不同的限制和要求。对于新卖家来说&#xff0c;他们可能会在特定的时间段内受到限制&#xff0c;比如30天或90天&#xff0c;限制他们在该类别下销售商品的数量或需要满足一定的条件才能进行销售。 这些限制的目的是保护买家免受潜在的欺诈和低质…

ubuntu 22.04 安装 minikube 和 istio

ubuntu 22.04 安装 minikube 和 istio 1. 使用 vmware 安装 ubuntu22.04 服务器 ​ 步骤简单&#xff0c;自己百度即可 2. 安装minikube 借鉴安装脚本&#xff1a; https://blog.csdn.net/LeoForBest/article/details/126524892 #!/usr/bin/bash # ~~~~~~~~~ # Ubuntu 22.…

Leetcode 【1155. 掷骰子等于目标和的方法数】

这里有 n 个一样的骰子&#xff0c;每个骰子上都有 k 个面&#xff0c;分别标号为 1 到 k 。 给定三个整数 n , k 和 target &#xff0c;返回可能的方式(从总共 kn 种方式中)滚动骰子的数量&#xff0c;使正面朝上的数字之和等于 target 。 答案可能很大&#xff0c;你需要…