UDP 简介

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

DatagramPacket 类

DatagramPacket 表示数据报,它的构造方法可以被分为两种:

  • 创建用来接收数据的 DatagramPacket 对象
  • 创建用来发送数据的 DatagramPacket 对象

两种构造方法的主要区别是:

  • 用于发送数据的构造方法需要设定数据报到达的目的地的地址
  • 用于接收数据的构造方法无须设定地址

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

//data:用来存放接收到的数据
//length:指定要接收的字节数
//offset:指定在data存放数据的起始位置,即data[offset],如果没有设定,那么初始位置为data[0]
public DatagramPacket(byte[] data, int length);
public DatagramPacket(bytel data, int offset, int length);

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

//data:用来存放要发送的数据
//length:指定要发送的字节数
//offset:指定在data要发送数据的起始位置,即data[offset],如果没有设定,那么初始位置为data[0]
//address和port:来指定目的地的地址
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);

DatagramPacket 类包括以下属性,提供了一系列 get/set 方法来获取或设置这些属性:

  • data:表示数据报的数据缓冲区
  • offset:表示数据报的数据缓冲区的起始位置
  • length: 表示数据报的长度
  • address:对于用于发送的数据报,address 属性表示数据报的目标地址。对于用于接收的数据报,address 属性表示发送者的地址
  • port:对于用于发送的数据报,port 属性表示数据报的目标 UDP 端口。对于用于接收的数据报,port 属性表示发送者的 UDP 端口

DatagramSocket 类

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

DatagramSocket 的构造方法有以下几种重载形式:

//由操作系统分配的任意的可用端口
DatagramSocket();
//显式指定本地端口
DatagramSocket(int port);
//同时指定IP和端口
DatagramSocket(int port, InetAddress laddr);
DatagramSocket(SocketAddress bindaddr);

DatagramSocket 的 send 方法负责发送一个数据报,该方法的定义如下:

public void send(DatagramPacket dp) throws IOException

值得注意的是,UDP 提供不可靠的传输,如果数据报没有到达目的地,那么 send 方法不会抛出任何异常,发送方程序就无法知道数据报是否被接收方接收到,除非双方通过应用层的特定协议来确保接收方未收到数据报时,发送方能重发数据报

DatagramSocket 的 receive 方法负责接收一个数据报,该方法的定义如下:

public void receive(DatagramPacket datagramPacket) throws IOException

此方法从网络上接收一个数据报,如果网络上没有数据报,执行该方法的线程就会进入阻塞状态,直到收到数据报为止。参数 datagramPacket 用来存放接收到的数据报,如果接收的数据报太大,receive 方法会在 datagramPacket 的数据缓冲区内存放尽可能多的数据,其余的数据则丢弃

两个 TCP Socket 之间存在固定的连接关系,而一个 DatagramSocket 可以与其他任意一个 DatagramSocket 交换数据报。在某些场合,一个 DatagramSocket 可能只希望与固定的另一个远程 DatagramSocket 通信,从 JDK1.2 开始,DatagramSocket 添加了一些方法,利用这些方法,可以使一个 DatagramSocket 只能与另一个固定的 DatagramSocket 交换数据报

//该方法实际上不建立TCP意义上的连接,但能限制当前DataramSocket只对参数指定的远程主机和UDP端口收发数据报
public void connect(InetAddress host, int port);
//中止当前DatagramSocket已经建立的连接
public void disconnect();
//当且仅当DatagramSocket已经建立连接时返回所连接的远程UDP端口,否则返回“-1”
public int getPort();
//当且仅当DatagramSocket已经建立连接时返回所连接的远程主机的IP地址,否则返回null
public InetAddress getlnetAddress();
//当且仅当DatagramSocket已经建立连接时返回所连接的SocketAddress,否则返回null
public SocketAddress getRemoteSocketAddress();

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

DatagramChannel 类

DatagramChannel 是 SelectableChannel 的子类,可以被注册到一个 Selector。使用 DatagramChannel,可以使 UDP 服务器只需用单个线程就能同时与多个客户通信。DatagramChannel 在默认情况下采用阻塞模式,如果希望该为非阻塞模式,那么可以调用 configureBlocking(false) 方法

DatagramChannel 类的静态 open 方法返回一个 DatagramChannel 对象,每个 DatagramChannel 对象都关联了一个 DatagramSocket 对象,DatagramChannel 对象的 socket 方法返回这个 DatagramSocket 对象

DatagramChannel 对象被创建后,与它关联的 DatagramSocket 对象还没有被绑定到任何地址,必须调用 DatagramSocket 对象的 bind 方法来与一个本地地址绑定

DatagramChannel channel = DatagramChannel.open();
DataqramSocket socket = channel.socket();
SocketAddress address = new InetSocketAddress(8000);
socket.bind(address);

与 DatagramSocket 一样,DatagramChannel 的 connect(SocketAddress remote) 方法使得通道只能对特定的远程地址收发数据报

DatagramChannel 使用 send 方法发送数据

//把参数src的剩余数据作为一个数据报写到通道中,参数target指定目标地址,该方法返回发送的字节数
public int send(ByteBuffer src, SocketAddress target) throws IOException

DatagramChannel 使用 receive 方法从通道中读取一个数据报,存放在参数指定的 ByteBufer,并返回数据报的发送方的地址

public SocketAddress receive(ByteBuffer dst) throws IOException

如果 DatagramChannel 工作于阻塞模式,那么 receive 方法在读取到数据报之前不会返回。如果 DatagramChannel 工作于非阻寒模式,那么 receive 方法在没有数据报可读取的情况下立即返回 null

DatagramChannel 也可以使用 write 方法发送数据,与 send 方法区别在于:write 方法要求 DatagramChannel 已经建立连接

public int write(ByteBuffer src) throws IOException;
//依次发送ByteBuffer数组中每个ByteBuffer的数据
public long write(ByteBufferl] srcs) throws IOException;
//参数offse指定ByteBuffer数组的起始位置参数,length指定发送的ByteBuffer的数目
public long write(ByteBufferl] srcs, int offset, int length) throws IOException;

DatagramChannel 也可以使用 read 方法接收数据,同样的,它也要求 DatagramChannel 已经建立连接

public int read(ByteBuffer src) throws IOException;
//把数据报的数据保存到 ByteBuffer 数组中
public long read(ByteBuffer[l srcs) throws IOException;
public long read(ByteBuffer[] srcs, int offset, int length) throws IOException;

Java 网络编程 —— 基于 UDP 的数据报和套接字的更多相关文章

  1. 【Java】Java网络编程菜鸟进阶:TCP和套接字入门

    Java网络编程菜鸟进阶:TCP和套接字入门 JDK 提供了对 TCP(Transmission Control Protocol,传输控制协议)和 UDP(User Datagram Protoco ...

  2. java网络编程(二)可中断套接字

    参考资料:java核心技术 卷II 为中断套接字操作,可使用java.nio包提供的SocketChannel类.可以使用如下方式打开SocketChannel: SocketChannel chan ...

  3. Java 网络编程 --基于UDP实现一对一聊天功能

    UDP 基本流程: UDP发送端基本流程: 1.使用DatagramSocket 指定端口 创建发送端 2.准备数据 一定转成字节数组 3. 封装成DatagramPacket 包裹,需要指定目的地 ...

  4. Java 网络编程 -- 基于TCP 模拟多用户登录

    Java TCP的基本操作参考前一篇:Java 网络编程 – 基于TCP实现文件上传 实现多用户操作之前先实现以下单用户操作,假设目前有一个用户: 账号:zs 密码:123 服务端: public c ...

  5. java网络编程--4 UDP

    java网络编程--4 UDP 1.7.UDP 发短信:不用连接,但是需要知道对方的地址 主要包含两个类:DatagramPacket 和 DatagramSocket 发送消息 发送端: packa ...

  6. Learning-Python【30】:基于UDP协议通信的套接字

    UDP协议没有粘包问题,但是缓冲区大小要足够装数据包大小,建议不要超过 512 服务端: # 服务端 import socket server = socket.socket(socket.AF_IN ...

  7. Linux 网络编程详解一(IP套接字结构体、网络字节序,地址转换函数)

    IPv4套接字地址结构 struct sockaddr_in { uint8_t sinlen;(4个字节) sa_family_t sin_family;(4个字节) in_port_t sin_p ...

  8. JAVA基础知识之网络编程——-基于UDP协议的通信例子

    UDP是一种不可靠的协议,它在通信两端各建立一个socket,这两个socket不会建立持久的通信连接,只会单方面向对方发送数据,不检查发送结果. java中基于UDP协议的通信使用DatagramS ...

  9. java 网络编程基础 UDP协议的Socket:DatagramSocket;广播Socket:MulticastSocket

    什么是UDP协议: UDP协议是一种不可靠的网络协议,它在通信实例的两端各建立一个Socket 但这两个 Socket之间并没有虚拟链路,这两个Socket只是发送.接收数据报的对象.Java 提供了 ...

  10. java Socket编程-基于UDP

    package com.wzy.UDPTest; import java.net.DatagramPacket; import java.net.DatagramSocket; import java ...

随机推荐

  1. [Python] Turtle库的运用, 创作精美绘画

    更多示例代码下载地址 : https://github.com/Amd794/Python123 前言 最初来自于 Wally Feurzig 和 Seymour Papert 于 1966 年所创造 ...

  2. Lyndon 分解

    介绍 [模板]Lyndon 分解 #include<cstdio> #include<cstring> char s[5000005]; int main(){ scanf(& ...

  3. 一步解决Cannot resolve symbol 'WebServlet'(@WebServlet注解标红)

    右键项目名(javaweb01)->Open Module Settings Modules->Dependencies->点击Export上面的,添加Tomcat即可

  4. [Codechef REBXOR]Nikitosh and xor (Trie,异或)

    题目传送门 分析:首次考虑暴力枚举 \(l_{1},r_{1},l_{2},r_{2}\),配合前缀和时间复杂度 \(O(N^{4})\),需要想办法优化.对于这种两段区间不重合的,我们考虑枚举两段区 ...

  5. 关于fstream对象的open方法报错183的问题

    当使用fstream,ifstream,ofstream,这几种对象打开文件, 但文件已经存在的时候, 调用GetLastError()函数,会返回错误代码183, 这个代码代表该文件已经存在,是正常 ...

  6. jmeter测试计划中的“独立运行每个线程组”Demo演示

    一:jmeter的运行顺序 测试计划-->线程组 其次执行顺序为:配置元件.前置处理器.定时器.取样器.后置处理器.断言.监听器 当一个测试计划中有多个线程组,当多个线程组都是是执行状态时,就会 ...

  7. Vue2.0 学习 第二组 语法模板

    本笔记主要参考菜鸟教程和官方文档编写. 1.文本绑定 一般在dom中用{{}}标时,并且在vue构造体内的data中定义文本内容 <div id="app">    & ...

  8. 使用pip或者手动安装第三方库出现“由于目标计算机积极拒绝,无法连接”错误的解决办法

    网上找了很多地方,都没找到怎么解决,之前用pip安装成功过,但是翻过墙后,pip安装第三方库的时候发现错误,如图:

  9. 面试官:说一下MySQL主从复制的原理?

    MySQL 主从复制(Master-Slave Replication)是一种数据复制技术,用于在多个数据库服务器之间的数据同步.在主从复制架构中,一个服务器被设置为主服务器(Master),充当数据 ...

  10. 谷粒学院通用工具类R类

    import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.util.HashMap; import ...