网络编程套接字之UDP

news2025/1/19 14:21:31

在这里插入图片描述

文章目录

  • 一、网络编程
  • 二、UDP数据报套接字编程
    • DatagramSocket
    • DatagramPacket
    • 实现客户端服务器程序
      • EchoServer
      • 客户端

一、网络编程

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

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

TCP:
特点:

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

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

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

二、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省略了这一部分,接收到什么就返回什么。

EchoServer

我们网络编程,本质上是要操作网卡,但是网卡不方便我们直接操作,于是我们操作系统内核中,使用“socket"这样的文件来抽象表示网卡,所以我们要想进行网络通信,首先得有一个socket对象

public class EchoServer {
    private DatagramSocket socket = null;
}

我们的服务器,在真正创建对象的时候,需要绑定一个具体的端口号,为啥是具体的呢?因为我们的服务器在进行网络通信中,是属于比较被动的一方,如果我们使用的是系统随机进行分配的端口号,那么我们的客户端就不知道服务器端口号是多少,也就无法进行通信了。

public EchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }

我们的UDP传输的基本单位是DatagramPacket.
在这里插入图片描述
此时我们服务器接收到的DatagramPacket是一个特殊的对象,并不方便我们直接进行处理,我们可以把这里包含的数据拿出来,构造成一个字符串。

String request = new String(requestPcket.getData(),0, requestPcket.getLength());

在这里插入图片描述
我们在创建DatagramPacket给的最大长度是4096,但我们实际可能只用了一小部分,因此我们在构造字符串时,通过getLength()获取数据报实际的长度。
我们获取到了客户端的请求之后然后我们对请求进行处理,我们这里实现的是接收什么,回应什么。
在这里插入图片描述

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

然后我们将这个响应发送给客户端,首先我们需要构造出DatagramPacket对象。

DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length);

因为我们的DatagramPacket不认字符只认字节,所以我们将response转换为字节数组。
在这里插入图片描述
答案是不可以,因为response.length()获取的是字符的个数,response.getBytes().length获取的是字节的个数。
我们这里的DatagramPacket的构造还是有一点点问题,我们这里的数据是构建好了,那给谁发呢?

DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPcket.getSocketAddress());

我们在参数中,应该传入客户端的地址信息。
在这里插入图片描述
然后进行发送

socket.send(responsePacket);

在这里插入图片描述
数据到达网卡,经过内核层层分用,最终到达了UDP传输层协议,调用receive相当于是执行内核中udp相关的代码,将UDP数据报的载荷取出来,拷贝到用户提供的byte[] 数组中。

public class EchoServer {
    private DatagramSocket socket = null;
    public EchoServer(int port) throws SocketException {
        socket = new DatagramSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        while (true) {
            DatagramPacket requestPcket = new DatagramPacket(new byte[4096],4096);
            socket.receive(requestPcket);
            String request = new String(requestPcket.getData(),0, requestPcket.getLength());
            String response = process(request);
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,
                    requestPcket.getSocketAddress());
            socket.send(responsePacket);
            //打印本次请求响应的结果
            System.out.printf("[%s:%d] req: %s; resp: %s\n",requestPcket.getAddress().toString(),
                    requestPcket.getPort(),request,response);
        }
    }
    public String process(String request) {
        return request;
    }
}

客户端

我们在构造客户端Socket对象时,不需要显式的去绑定一个端口,而是由系统分配一个空闲端口。

服务器的端口:需要固定指定,为了方便客户端找到服务器程序。
客户端的端口:由系统自动分配的,如果我们手动指定,可能会与客户端其他程序的端口冲突
为什么服务器不怕冲突?
因为服务器上面的程序可控,而客户端是运行在我们用户电脑上,环境复杂,更不可控。

首先我们需要创建一个Socket对象,并且获取服务器的ip和端口号

private DatagramSocket socket = null;
    private String serverIp = null;
    private int serverPort = 0;
    
    public EchoClient(String serverIp,int serverPort) throws SocketException {
        socket = new DatagramSocket();
        this.serverIp = serverIp;
        this.serverPort = serverPort;
    }

我们一次网络通信涉及到五元组:
源IP,源端口,目的IP,目的端口,协议类型。

然后从控制台接收我们需要发送端数据。

System.out.print("> ");
            String request = scan.next();
            if(request.equals("exit")) {
                System.out.println("客户端退出");
                break;
            }

我们将request字符串构造成DatagramPacket进行发送。

DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,
                    InetAddress.getByName(serverIp),serverPort);

我们在构造DatagramPacket的时候,需要将ip和端口号都传入,此处需要传入的IP是32位的整数形式,但我们这里的ip是字符串,所以需要使用InetAddress.getByName进行转换,然后进行发送。

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 class EchoClient {
    private DatagramSocket socket = null;
    private String serverIp = null;
    private int serverPort = 0;

    public EchoClient(String serverIp,int serverPort) throws SocketException {
        socket = new DatagramSocket();
        this.serverIp = serverIp;
        this.serverPort = serverPort;
    }

    public void start() throws IOException {
        System.out.println("客户端启动!");
        Scanner scan = new Scanner(System.in);
        while (true) {
            System.out.print("> ");
            String request = scan.next();
            if(request.equals("exit")) {
                System.out.println("客户端退出");
                break;
            }
            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);
        }
    }
}

在这里插入图片描述
在这里插入图片描述
我们分别启动客户端和服务器
在这里插入图片描述
在这里插入图片描述
我们此处显示的客户端IP是环回IP,端口号是系统随机分配的。
我们客户端服务器程序,一个服务器是给许多客户端提供服务的,但是我们IDEA默认只能启动一个客户端,我们需要手动设置一下。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
现在我们就可以创建多客户端与服务器进行通信了。
端口冲突
一个端口只能被一个进程使用,如果有多个使用就不行。
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/197576.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot+Vue+Wx健康上报系统

简介:本项目采用了基本的springbootvueWx设计健康上报系统。详情请看截图。经测试,本项目正常运行。本项目适用于Java毕业设计、课程设计学习参考等用途。 项目描述 项目名称SpringBootVueWx健康上报系统源码作者LHL项目类型Java EE项目 (前…

多线程初阶——线程状态

多线程初阶——线程状态 文章目录多线程初阶——线程状态1.Thread类及常见构造方法2.Thread常见的方法3.线程相关的重要操作3.1启动线程—start()3.2中断线程3.3 等待线程— join()3.4 获取线程引用3.5休眠线程—sleep()4.线程的状态1.Thread类及常见构造方法 方法说明Thread(…

前端js实现根据文件url批量压缩下载成zip包

前言 项目开发中,产品经理提了这样一个需求:将系统中的附件实现批量打包下载功能。本来系统中是有单个下载及批量下载功能,现在应业务方的需求,需要多加个批量打包下载。 初步设想是:由后端编写接口实现。但后来经过思…

从事测试开发8年,聊聊我是怎么从0基础到年薪40万的

本人从事测试开发8年多,之前在猪场工作,年薪突破40W,算是一个生活过得去的码农。(仅代表本人)目前从事软件测试行业的薪资待遇还是很不错的,所以如果朋友们真的对软件测试感兴趣的话可以坚持学下去&#xf…

Java native agent学习笔记-从加载到log4j漏洞检测

记录一下java native agent的学习过程,也顺便造一个检测log4j漏洞的轮子: java native agent相比java agent最大的好处是快,C写的,快的一笔,但是最大的坏处是非常麻烦,毕竟你拿个面过程的语言怼面对象的肯定是比较麻烦的。 本次学习的目的是做个加载器,动态加载agent,然后再实…

研究人员发布 VMware vRealize Log RCE 漏洞,立即打补丁

Horizon3 攻击团队的安全研究人员将于下周发布一个针对漏洞链的漏洞利用程序,以在未打补丁的 VMware vRealize Log Insight 设备上获得远程代码执行。 vRealize Log Insight 现在称为 VMware Aria Operations for Logs,它使 VMware 管理员可以更轻松地分…

每日学术速递2.4

CV - 计算机视觉 | ML - 机器学习 | RL - 强化学习 | NLP 自然语言处理 Subjects: cs.LG、cs.AI 1.Neuro Symbolic Continual Learning: Knowledge, Reasoning Shortcuts and Concept Rehearsal 标题:神经象征性的持续学习:知识、推理捷径和概念排练…

必须掌握的网络安全知识

没有网络安全,就没有国家安全。网络安全和保密防护,是机关单位日常工作中不可忽视的重要问题。尤其在涉密单位工作的人员,因工作性质特殊,不仅要了解非涉密网络的安全操作常识,更要重点了解涉密网络的规范行为要点&…

2021年上半年信息系统项目管理师真题与答案完整版(综合知识、案例分析、论文)

1、 国家信息化体系包括六个要素,其中()是信息化体系六要素中的龙头,是国家信息化建设的主阵地,集中体现了国家信息化建设的需求和效益。A、信息资源 B、信息技术应用 C、信息网络 D、信息化政策法规和标准规范0参考答…

若依代码生成器------数据库篇

继上一篇《若依代码自动生成器研究-表查询篇》,我们继续来学习若依系统中的代码生成逻辑。 导入表之Sql查询 在菜单栏点击“代码生成”,在右侧栏中点击“导入”按钮,在文章若依中的代码自动生成器研究-表查询篇中,我们已经一直…

三十六、Kubernetes1.25中数据存储第一篇

1、概述在前面已经提到,容器的生命周期可能很短,会被频繁地创建和销毁。那么容器在销毁时,保存在容器中的数据也会被清除。这种结果对用户来说,在某些情况下是不乐意看到的。为了持久化保存容器的数据,kubernetes引入了…

【深度学习】对SSD与Retina的理解

SSD 正负样本选择 同YOLO 选择与GT IOU最大的anchor作为正样本。(此时正负样本很不平衡)对于剩余未匹配anchor,将与GT IOU超过0.5的作为正样本。这样一个GT就可以匹配多个anchor,增加正样本的数量。(此时负样本依然多于正样本)hard negative mining,难负样本挖掘。将所有…

重定向的概述和使用(基于web方面),很简单

大家好,今天分享一下重定向的概述以及使用 我们要知道,重定向(Redirect)就是通过各种方法将各种网络请求重新定个方向转到其它位置 同时,重定向有好几类 1.网页重定向、 2.域名的重定向、 3.路由选择 4. Linux上的文件重定向操作 就是要知…

QTransform的使用

目录引言基础知识缩放矩阵平移矩阵旋转矩阵矩阵乘法实际使用实现思路完整代码参考资料引言 A transformation specifies how to translate, scale, shear, rotate or project the coordinate system, and is typically used when rendering graphics. A QTransform object can …

6 -【Faster R-CNN 代码精读】之 Proposals 、 Filter Proposals

6 -【Faster R-CNN 代码精读】之 Proposals 、 Filter Proposals1、前言2、数据回顾3、计算候选框位置(proposal coordinates)4、筛选候选框(filter proposals)及相关处理1)筛选出 预测概率 排前 2000 的proposals2&am…

TCP协议面试灵魂12 问(四)

005: 介绍一下 TCP 报文头部的字段 报文头部结构如下(单位为字节): 请大家牢记这张图! 源端口、目标端口 如何标识唯一标识一个连接?答案是 TCP 连接的四元组——源 IP、源端口、目标 IP 和目标端口。 那 TCP 报文怎么没有源 IP 和目标 IP 呢&#x…

2021年下半年信息系统项目管理师《综合知识》《案例分析》《论文》真题与答案

1、“十四五”期间,我国关注推动政务信息化共建共用、推动构建网络空间命运共同体,属于()的建设内容.A、科技中国 B、数字中国 C、制造强国 D、创新强国0参考答案:B2、()关注的是业务,以业务驱动技术,强调IT与业务的对…

零基础学FPGA(八):可编程逻辑单元(基本结构,Xilinx+Altera)

目录日常唠嗑一、概述二、基于多路选择器的逻辑单元1、基于多路选择器的逻辑单元(早期)2、基于PLD结构的逻辑单元(类CPLD)3、基于查询表的逻辑单元(目前主流)三、Xilinx基本结构四、Altera 基本结构日常唠嗑…

Java语言还能火多久? 还能选择Java开发吗?

​​整个互联网行业“不进则退,慢进亦退”。对于用人要求持续增高的互联网企业来说,中高级Java程序员才是当下市场最紧缺的。 现在的你,是十年前你的决定,十年后的你,是现在你的决定。选择很重要 为什么选择Java开发…

代码随想录算法训练营第六十天_第九章_动态规划 | 647. 回文子串、516.最长回文子序列、动态规划总结篇

LeetCode 647. 回文子串 给你一个字符串 s ,请你统计并返回这个字符串中 回文子串 的数目。具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被视作不同的子串。 视频讲解https://www.bilibili.com/video/BV17G4y1y7z9/?spm_i…