Java网络编程——基于UDP的数据报和套接字

java.net.ServerSocket与java.net.Socket建立在TCP的基础上。TCP是网络传输层的一种可靠的数据传输协议。如果数据在传输途中被丢失或损坏,那么TCP会保证再次发送数据;如果数据到达接收方的顺序被打乱,那么TCP会在接收方重新恢复数据的正确顺序。应用层无须担心接收到乱序或错误的数据,应用层只需从Socket中获得输入流和输出流,就可以方便地接收和发送数据。当发送方先发送字符串“hello”,再发送字符串“everyone”时,接收方在应用层必定先接收到字符串“hello”,再接收到字符串“everyone”。接收方不会先接收到字符串“everyone”,再接收到字符串“hello”。

TCP的可靠性是有代价的,这种代价就是传输速度的降低。建立和销毁TCP连接会花费很长的时间。如果通信双方实际上通信的时间很短,要传输的数据很少,那么建立和销毁TCP连接的代价就相对较高。

UDP(User Datagram Protocol,用户数据报协议)是传输层的另一种协议,它比TCP具有更快的传输速度,但是不可靠。UDP发送的数据单元被称为UDP数据报。当网络传输UDP数据报时,无法保证数据报一定到达目的地,也无法保证各个数据报按发送的顺序到达目的地。当发送方先发送包含字符串“hello”的数据报,再发送包含字符串“everyone”的数据报时,接收方有可能先接收到字符串“everyone”,再接收到字符串“hello”;也有可能什么数据也没有接收到,因为发送方发送的数据有可能在传输途中都被丢失了。

1、UDP简介

如果应用层关心数据能否正确到达,那么就应该在传输层使用TCP。例如应用层的FTP和HTTP都建立在TCP的基础上。如果应用层仅关心发送的数据能否快速到达目的地,则可以考虑在传输层使用UDP。例如,用UDP传输实时音频时,如果丢失了数据报或打乱数据报的顺序,则只会导致接收方出现噪音,而适量的噪音是可以容忍的。但是如果用TCP传输实时音频,则由于速度很慢,会导致接收方常常出现停顿,声音时断时续,这是无法容忍的。由此可见,UDP比TCP更适于传输实时音频。

由于UDP传输数据是不可靠的,假如应用层要求接收到正确的数据,那么应用层自身必须保证数据传输的可靠性。应用层的网络文件系统(Network File System,NFS)协议,以及简单文件传输协议(Trivial FTP,TFTP)协议都建立在UDP的基础上。NFS协议和TFTP会保证可靠性,这意味着实现NFS协议或TFTP的应用程序必须处理丢失或乱序的数据报。

建立在UDP上的应用层如何保证数据传输的可靠性呢?这可以用邮局发送邮包来做解释,邮局就相当于UDP的实现者,它提供不可靠的传输。发送者通过邮局先后发送3个邮包,邮包上写明了接收者的地址,邮局把邮包发送给接收者,但是有可能部分邮包在途中被丢失,也有可能邮包到达目的地的先后顺序与发送的先后顺序不一样。发送者与接收者必须事先商量好确保接收者正确接收到邮包的协议。发送者会在邮包上标上序号,接收者收到邮包后就能按照序号排序。接收者会告诉发送者已经收到了哪些邮包,发送者就能重发那些接收者未收到的邮包。发送者与接收者使用的这种协议就相当于应用层的协议。

在Java中,java.net.DatagramSocket负责接收和发送UDP数据报,java.net.DatagramPacket表示UDP数据报。如下图所示,每个DatagramSocket都与一个本地地址(包括本地主机的IP地址和本地UDP端口)绑定,每个DatagramSocket都可以把UDP数据报发送给任意一个远程DatagramSocket,也都可以接收来自任意一个远程DatagramSocket的UDP数据报。在UDP数据报中包含了目的地址的信息,DatagramSocket根据该信息把数据报发送到目的地。
在这里插入图片描述
采用TCP通信时,客户端的Socket必须先与服务器建立连接,连接建立成功后,服务器端也会持有与客户连接的Socket,客户端的Socket与服务器端的Socket是一一对应的,它们构成了两个端点之间的虚拟的通信线路。

而UDP是无连接的协议,客户端的DatagramSocket与服务器端的DatagramSocket不存在一一对应关系,两者无须建立连接,就能交换数据报。DatagramSocket提供了接收和发送数据报的方法。

  • public void receive(DatagramPacket dst)throws IOException //接收数据报
  • public void send(DatagramPacket src)throws IOException //发送数据报

下面的EchoServer与例EchoClient就利用DatagramSocket来发送和接收数据报。在这里插入图片描述

在这里插入图片描述
在同一时刻,可能会有多个EchoClient进程与EchoServer进程通信。EchoServer的DatagramSocket与UDP端口8000绑定,EchoClient则与任意一个可用的UDP端口绑定。EchoServer在一个while循环中不断接收EchoClient的数据报,然后给EchoClient回复一个数据报。

EchoClient从控制台读取用户输入的字符串,把它包装成一个数据报,然后把它发送给EchoServer,接着再接收EchoServer的响应数据报。

值得注意的是,EchoClient与EchoServer之间的通信是不可靠的,EchoClient以及EchoServer发送的数据报有可能丢失,或者各个数据报到达目的地的顺序与发送数据报的顺序不一致。

2、DatagramPacket类

DatagramPacket表示数据报,它的构造方法可以被分为两种:一种构造方法创建的DatagramPacket对象用来接收数据,还有一种构造方法创建的DatagramPacket对象用来发送数据。两种构造方法的主要区别是,用于发送数据的构造方法需要设定数据报到达的目的地的地址,而用于接收数据的构造方法无须设定地址。

用于接收数据的构造方法包括:

  • public DatagramPacket(byte[] data,int length)
  • public DatagramPacket(byte[] data,int offset,int length)

以上data参数被用来存放接收到的数据,参数length指定要接收的字节数,参数offset指定在data中存放数据的起始位置,即data[offset]。如果没有设定参数offset,那么起始位置为data[0]。参数length必须小于或等于data.length-offset,否则会抛出IllegalArgumentException。

用于发送数据的构造方法包括:

  • public DatagramPacket(byte[] data,int offset,int length,InetAddress address,int port)
  • public DatagramPacket(byte[] data,int offset,int length,SocketAddress address)
  • public DatagramPacket(byte[] data,int length,InetAddress address,int port)
  • public DatagramPacket(byte[] data,int length,SocketAddress address)

以上data参数中存放了要发送的数据,参数length指定要发送的字节数,参数offset指定要发送的数据在data中的起始位置,即data[offset]。如果没有设定参数offset,那么起始位置为data[0]。参数length必须小于或等于data.length-offset,否则会抛出IllegalArgumentException。参数address和参数port用来指定目的地的地址。以下两段程序代码都创建了一个数据报,它的送达地址为主机“myhost”的UDP端口100。
在这里插入图片描述

3、DatagramSocket类

DatagramSocket类负责接收和发送数据报。每个DatagramSocket对象都会与一个本地端口绑定,在此端口监听发送过来的数据报。在客户程序中,一般由操作系统为DatagramSocket类分配本地端口,这种端口也被称为匿名端口。在服务器程序中,一般由程序显式地为DatagramSocket类指定本地端口。

3.1、构造DatagramSocket

DatagramSocket的构造方法有以下几种重载形式:
在这里插入图片描述
第1个不带参数的构造方法使DatagramSocket对象与匿名端口绑定(即由操作系统分配的任意的可用端口),其余的构造方法都会显式地指定本地端口。第3和第4个构造方法需要同时指定IP地址和端口,这适用于一个主机有多个IP地址的场合,这两个构造方法能明确指定DatagramSocket对象所绑定的IP地址。

如果想知道一个DatagramSocket对象所绑定的本地地址,那么可以调用它的以下方法:

  • int getLocalPort():返回DatagramSocket所绑定的端口。
  • InetAddress getLocalAddress():返回DatagramSocket所绑定的IP地址。
  • SocketAddress getLocalSocketAddress():返回一个SocketAddress对象,它包含DatagramSocket所绑定的IP地址和端口信息。

3.2、接收和发送数据报

DatagramSocket的send()方法负责发送一个数据报,该方法的定义如下:
在这里插入图片描述
值得注意的是,UDP提供不可靠的传输,如果数据报没有到达目的地,那么send()方法不会抛出任何异常,发送方程序就无法知道数据报是否被接收方接收到,除非双方通过应用层的特定协议来确保接收方未收到数据报时,发送方能重发数据报。

send()方法可能会抛出IOException,但是与java.uti.Socket相比,DatagramSocket的send()方法抛出IOException的可能性很小。如果发送的数据报超过了底层网络所支持的数据报的大小,就可能会抛出SocketException,它是IOException的子类。
在这里插入图片描述
DatagramSocket的receive()方法负责接收一个数据报,该方法的定义如下:
在这里插入图片描述
此方法从网络上接收一个数据报。如果网络上没有数据报,执行该方法的线程就会进入阻塞状态,直到收到数据报为止。

参数datagramPacket用来存放接收到的数据报,datagramPacket的数据缓冲区应当足够大,以存放接收到的数据。否则,如果接收的数据报太大,receive()方法就会在datagramPacket的数据缓冲区内存放尽可能多的数据,其余的数据则被丢失。

如果接收数据时出现问题,receive()方法就会抛出IOException,但这种情况实际上极少出现。

3.3、管理连接

两个TCP Socket之间存在固定的连接关系,而一个DatagramSocket可以与其他任意一个DatagramSocket交换数据报。

在某些场合,一个DatagramSocket可能只希望与固定的另一个远程DatagramSocket通信。例如,NFS客户只接收来自与之通信的服务器的数据报。再例如,在网络游戏中,一个游戏玩家只接收他的游戏搭档的数据报。

从JDK1.2开始,DatagramSocket添加了一些方法,利用这些方法,可以使一个DatagramSocket只能与另一个固定的DatagramSocket交换数据报:

  • (1)public void connect(InetAddress host,int port):connect()方法实际上不建立TCP意义上的连接,但它能限制当前DatagramSocket只对参数指定的远程主机和UDP端口收发数据报。如果当前DatagramSocket试图对其他的主机或UDP端口发送数据报,send()方法就会抛出IllegalArgumentException。从参数以外的其他主机或UDP端口发送过来的数据报则被丢弃,程序不会得到任何通知,也不会抛出任何异常。
  • (2)public void disconnect():disconnect()中止当前DatagramSocket已经建立的“连接”,这样,DatagramSocket就可以再次对任何其他主机和UDP端口收发数据报。
  • (3)public int getPort()当且仅当DatagramSocket已经建立连接时,getPort()方法才返回DatagramSocket所连接的远程UDP端口,否则返回“-1”。
  • (4)public InetAddress getInetAddress()当且仅当DatagramSocket已经建立连接时,getInetAddress()方法才返回DatagramSocket所连接的远程主机的IP地址,否则返回null。
  • (5)public SocketAddress getRemoteSocketAddress()当且仅当DatagramSocket已经建立连接时,getRemoteSocketAddress()方法才返回一个SocketAddress对象,表示DatagramSocket所连接的远程主机以及端口的地址,否则返回null。

UDP客户程序通常只和特定的UDP服务器通信,因此可在UDP客户程序中把DatagramSocket与远程服务器连接。UDP服务器需要与多个UDP客户程序通信,因此在UDP服务器中一般不用对DatagramSocket建立特定的连接。

3.4、关闭DatagramSocket

DatagramSocket的close()方法会释放所占用的本地UDP端口。在程序中及时关闭不再需要的DatagramSocket,这是好的编程习惯。

3.5、DatagramSocket的选项

DatagramSocket有以下选项:

  • SO_TIMEOUT:表示接收数据报时的等待超时时间。
  • SO_RCVBUF:表示接收数据的缓冲区的大小。
  • SO_SNDBUF:表示发送数据的缓冲区的大小。
  • SO_REUSEADDR:表示是否允许重用DatagramSocket所绑定的本地地址。
  • SO_BROADCAST:表示是否允许对网络广播地址发送广播数据报。

3.6、IP服务类型选项

UDP与TCP都建立在IP基础之上,DatagramSocket也提供了设置和读取IP服务类型的方法:

  • 设置服务类型:public void setTrafficClass(int trafficClass) throws SocketException
  • 读取服务类型:public int getTrafficClass() throws SocketException

4、DatagramChannel类

从JDK1.4开始,添加了一个支持按照非阻塞方式发送和接收数据报的DatagramChannel。DatagramChannel是SelectableChannel的子类,可以被注册到一个Selector。使用DatagramChannel,可以使得UDP服务器只需用单个线程就能同时与多个客户通信。DatagramChannel在默认情况下采用阻塞模式,如果希望该为非阻塞模式,那么可以调用configureBlocking(false)方法。

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

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

相关文章

vscode报错Pylance client: couldn‘t create connection to server.

问题描述: 一打开vscode,右下角就弹报错,Pylance client: couldn’t create connection to server.,让我打开output,打开后似乎是在说连不上server 因为连不上server,所以我的python代码没法解析&#xff0…

2.4 C语言之运算符

2.4 C语言之运算符 一、算术运算符二、关系运算符三、逻辑运算符四、自增自减运算符五、按位运算符六、赋值运算符七、条件表达式八、运算符优先级与求值次序 一、算术运算符 二元算术运算符包括:(加)、-(减)、*(乘)、/(除)、%(取模) 整数除法会截断结果中的小数部…

扬声器(喇叭)

扬声器(喇叭) 电子元器件百科 文章目录 扬声器(喇叭)前言一、扬声器(喇叭)是什么二、扬声器(喇叭)的类别三、扬声器(喇叭)的应用场景四、扬声器(喇叭)的作用原理总结前言 扬声器广泛应用于音响系统、公共广播系统、汽车音响、电视、电脑和移动设备等各种电子设备…

Linux基本开发工具

编译器和自动化构建工具 一、编译器——gcc、g1. 安装 gcc/g2. 使用3. 链接库4. 拓展命令:od/file/ldd/readelf 二、自动化构建项目——make、makefile1. 介绍2. 使用例子touch——change file timestampsstat——display file or file system status修改时间 .PHON…

Qt 文字描边(基础篇)

项目中有时需要文字描边的功能 1.基础的绘制文字 使用drawtext处理 void MainWindow::paintEvent(QPaintEvent *event) {QPainter painter(this);painter.setRenderHint(QPainter::Antialiasing, true);painter.setRenderHint(QPainter::SmoothPixmapTransform, true);painte…

ceph的osd盘删除操作和iscsi扩展

ceph的osd盘删除操作 拓展:osd磁盘的删除(这里以删除node1上的osd.0磁盘为例) 1, 查看osd磁盘状态 [rootnode1 ceph]# ceph osd tree ID CLASS WEIGHT TYPE NAME STATUS REWEIGHT PRI-AFF -1 0.00298 root default -3 0.00099 host node10 hdd 0.00…

【Vins轨迹】pose_graph位姿图加载EVO精度评定

1. Vins的位姿图加载功能 如果想要对slam运行后的位姿轨迹进行评定,需要将数据保存到output文件夹中。 其中pose_graph.txt含有的信息:关键帧id、时间戳、vio的xyz、优化后的xyz、vio的四元数、优化后的四元数、回环到的关键帧id、回环信息&#xff08…

【Py/Java/C++三种语言OD2023C卷真题】20天拿下华为OD笔试【DP】2023C-分班【欧弟算法】全网注释最详细分类最全的华为OD真题题解

文章目录 题目描述与示例题目描述输入描述输出描述示例一输入输出 示例二输入输出 解题思路代码PythonJavaC时空复杂度 华为OD算法/大厂面试高频题算法练习冲刺训练 题目描述与示例 题目描述 幼儿园两个班的小朋友在排队时混在了一起,每位小朋友都知道自己是否与前…

【十】python复合模式

10.1 复合模式简介 在前面的栏目中我们了解了各种设计模式。正如我们所看到的,设计模式可分为三大类:结构型、创建型和行为型设计模式。同时,我们还给出了每种类型的相应示例。然而,在软件实现中,模式并是不孤立地工作的。对于所…

HPM5300系列--第一篇 命令行开发调试环境搭建

一、目的 在之前的博客中《HPM6750系列--第二篇 搭建Ubuntu开发环境》、 《HPM6750系列--第三篇 搭建MACOS编译和调试环境》我们介绍了HPM6750evkmini开发环境的搭建过程,由于HPM5300系列共用一套hpm-sdk,故HPM5300的开发调试环境的搭建过程基本和之前的…

golang学习笔记——互斥锁sync.Mutex、计数器sync.WaitGroup、读写锁sync.RWMutex

文章目录 互斥锁: sync.Mutexsync.WaitGroup 计数器例子func (*WaitGroup) Addfunc (*WaitGroup) Donefunc (*WaitGroup) Wait 读写互斥锁参考资料 临界区总是需要通过同步机制进行保护的,否则就会产生竞态条件,导致数据不一致。 互斥锁&…

智能故障诊断期刊推荐【中文期刊】

控制与决策 http://kzyjc.alljournals.cn/kzyjc/home 兵工学报 http://www.co-journal.com/CN/1000-1093/home.shtml 计算机集成制造系统 http://jsjjc.soripan.net/ 机械工程学报 http://www.cjmenet.com.cn/CN/0577-6686/home.shtml 太阳能学报 https://www.tynxb.org.c…

Visual Studio Code中的任务配置文件tasks.json中的可选任务组tasks详解

☞ ░ 前往老猿Python博客 ░ https://blog.csdn.net/LaoYuanPython 一、引言 vscode是支持通过配置可以实现类似Visual C等IDE开发工具使用菜单和快捷键直接进行程序编译构建的,这样构建的任务可以结合后续的调试配置进行IDE环境的程序调试,不过在之前…

12. IO

1.File类 • File 类代表与平台无关的文件和目录。 • File 能新建、删除、重命名文件和目录,但 File 不能访问文件内容本身。如果需要访问文件内容本身,则需要使用输入/输出流。 1).File的常用方法 在这里插入图片描述 2).遍历给定目录所有文件 …

Android源码下载流程

1.使用repo方式: https://github.com/jeanboydev/Android-ReadTheFuckingSourceCode/blob/master/article/android/framework/Android-Windows%E7%8E%AF%E5%A2%83%E4%B8%8B%E8%BD%BD%E6%BA%90%E7%A0%81.md 2.使用git方式: Windows 环境下载 Android 源…

QT之QMatrix

QT之QMatrix 成员函数介绍使用注意函数的使用 成员函数介绍 reset():将矩阵重置为单位矩阵(无变换)。 translate():执行平移变换。例如,translate(qreal dx, qreal dy)将图形沿x轴和y轴方向分别平移dx和dy个单位。 sc…

MySQL增删改查

查询数据 MySQL 数据库使用 SQL SELECT 语句来查询数据。以下为在 MySQL 数据库中查询数据通用的 SELECT 语法: SELECT column_name,column_name FROM table_name [WHERE Clause] [LIMIT N][ OFFSET M] 查询语句中你可以使用一个或者多个表,表之间使用…

联想笔记本如何安装Vmware ESXi

环境: Vmware ESXi 8.0 Vmware ESXi 6.7 联想E14笔记本 问题描述: 联想笔记本如何安装Vmware ESXi 解决方案: 1.官网下载镜像文件 https://customerconnect.vmware.com/en/downloads/search?queryesxi%208 下载 2.没有账户注册一个 …

什么时候使用匿名类,匿名类解决了什么问题?为什么需要匿名类 ?

匿名类通常在以下场景下使用: 一次性使用: 当你需要创建一个类的实例,但该类只在一个地方使用,而不打算在其他地方重复使用时,可以考虑使用匿名类。 简化代码: 当创建一个小型的、一次性的类会让代码更简洁…

浅析特征增强个性化在CTR预估中的经典方法和效果对比

在CTR预估中,主流都采用特征embeddingMLP的方式,其中特征非常关键。然而对于相同的特征,在不同的样本中,表征是相同的,这种方式输入到下游模型,会限制模型的表达能力。为了解决这个问题,CTR预估…