JAVA网络编程之UDP

简介:

上一篇博客中使用的Socket是基于TCP协议的,这一篇为大家简单介绍一下UDP协议。
UDP 是User Datagram Protocol的简称, 中文名是用户数据报协议,是OSI(Open System Interconnection,开放式系统互联) 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,IETF RFC 768是UDP的正式规范。
UDP协议全称是用户数据报协议[1] ,在网络中它与TCP协议一样用于处理数据包,是一种无连接的协议。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据包分组、组装和不能对数据包进行排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天UDP仍然不失为一项非常实用和可行的网络传输层协议。
与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。UDP协议的主要作用是将网络数据流量压缩成数据包的形式。一个典型的数据包就是一个二进制数据的传输单位。每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。

TCP与UDP的区别:
1. 基于连接与无连接;
2. 对系统资源的要求(TCP较多,UDP少);
3. UDP程序结构较简单;
4. 流模式与数据报模式 ;
5. TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

DatagramSocket

此类表示用来发送和接收数据报包的套接字。数据报套接字是包投递服务的发送或接收点。每个在数据报套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。
在 DatagramSocket 上总是启用 UDP 广播发送。为了接收广播包,应该将 DatagramSocket 绑定到通配符地址。在某些实现中,将 DatagramSocket 绑定到一个更加具体的地址时广播包也可以被接收。
示例:DatagramSocket s = new DatagramSocket(null); s.bind(new InetSocketAddress(8888)); 这等价于:DatagramSocket s = new DatagramSocket(8888); 两个例子都能创建能够在 UDP 8888 端口上接收广播的 DatagramSocket。

构造方法

方法名 说明
DatagramSocket() 构造数据报套接字并将其绑定到本地主机上任何可用的端口
DatagramSocket(int port) 创建数据报套接字并将其绑定到本地主机上的指定端口
DatagramSocket(int port, InetAddress laddr) 创建数据报套接字,将其绑定到指定的本地地址
DatagramSocket(SocketAddress bindaddr) 创建数据报套接字,将其绑定到指定的本地套接字地址

方法摘要

返回值 方法名 说明
void bind(SocketAddress addr) 将此 DatagramSocket 绑定到特定的地址和端口
void close() 关闭此数据报套接字
void connect(InetAddress address, int port) 将套接字连接到此套接字的远程地址
void connect(SocketAddress addr) 将此套接字连接到远程套接字地址(IP 地址 + 端口号)
void disconnect() 断开套接字的连接
boolean getBroadcast() 检测是否启用了 SO_BROADCAST
DatagramChannel getChannel() 返回与此数据报套接字关联的唯一 DatagramChannel 对象(如果有)
InetAddress getInetAddress() 返回此套接字连接的地址
InetAddress getLocalAddress() 获取套接字绑定的本地地址
int getLocalPort() 返回此套接字绑定的本地主机上的端口号
SocketAddress getLocalSocketAddress() 返回此套接字绑定的端点的地址,如果尚未绑定则返回 null
int getPort() 返回此套接字的端口
int getReceiveBufferSize() 获取此 DatagramSocket 的 SO_RCVBUF 选项的值,该值是平台在 DatagramSocket 上输入时使用的缓冲区大小
SocketAddress getRemoteSocketAddress() 返回此套接字连接的端点的地址,如果未连接则返回 null
boolean getReuseAddress() 检测是否启用了 SO_REUSEADDR
int getSendBufferSize() 获取此 DatagramSocket 的 SO_SNDBUF 选项的值,该值是平台在 DatagramSocket 上输出时使用的缓冲区大小
int getSoTimeout() 获取 SO_TIMEOUT 的设置
int getTrafficClass() 为从此 DatagramSocket 上发送的包获取 IP 数据报头中的流量类别或服务类型
boolean isBound() 返回套接字的绑定状态
boolean isClosed() 返回是否关闭了套接字
boolean isConnected() 返回套接字的连接状态
void receive(DatagramPacket p) 从此套接字接收数据报包
void send(DatagramPacket p) 从此套接字发送数据报包
void setBroadcast(boolean on) 启用/禁用 SO_BROADCAST
static void setDatagramSocketImplFactory(DatagramSocketImplFactory fac) 为应用程序设置数据报套接字实现工厂
void setReceiveBufferSize(int size) 将此 DatagramSocket 的 SO_RCVBUF 选项设置为指定的值
void setReuseAddress(boolean on) 启用/禁用 SO_REUSEADDR 套接字选项
void setSendBufferSize(int size) 将此 DatagramSocket 的 SO_SNDBUF 选项设置为指定的值
void setSoTimeout(int timeout) 启用/禁用带有指定超时值的 SO_TIMEOUT,以毫秒为单位
void setTrafficClass(int tc) 为从此 DatagramSocket 上发送的数据报在 IP 数据报头中设置流量类别 (traffic class) 或服务类型八位组 (type-of-service octet)。

DatagramPacket

此类表示数据报包。数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。不对包投递做出保证。

构造方法

方法名 说明
DatagramPacket(byte[] buf, int length) 构造 DatagramPacket,用来接收长度为 length 的数据包
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号
DatagramPacket(byte[] buf, int offset, int length) 构造 DatagramPacket,用来接收长度为 length 的包,在缓冲区中指定了偏移量
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号
DatagramPacket(byte[] buf, int offset, int length, SocketAddress address) 构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号
DatagramPacket(byte[] buf, int length, SocketAddress address) 构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号

方法摘要

返回值 方法名 说明
InetAddress getAddress() 返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的
byte[] getData() 返回数据缓冲区
int getLength() 返回将要发送或接收到的数据的长度
int getOffset() 返回将要发送或接收到的数据的偏移量
int getPort() 返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的
SocketAddress getSocketAddress() 获取要将此包发送到的或发出此数据报的远程主机的 SocketAddress(通常为 IP 地址 + 端口号)
void setAddress(InetAddress iaddr) 设置要将此数据报发往的那台机器的 IP 地址
void setData(byte[] buf) 为此包设置数据缓冲区
void setData(byte[] buf, int offset, int length) 为此包设置数据缓冲区
void setLength(int length) 为此包设置长度
void setPort(int iport) 设置要将此数据报发往的远程主机上的端口号
void setSocketAddress(SocketAddress address) 设置要将此数据报发往的远程主机的 SocketAddress(通常为 IP 地址 + 端口号)

使用示例

服务端

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * UDP服务端
 * 
 * @author jianggujin
 * 
 */
public class UDPServer
{
   public static void main(String[] args) throws IOException
   {
      DatagramSocket server = new DatagramSocket(9999);
      // 用于接收数据的缓冲数组
      byte[] recvBuf = new byte[100];
      // 实例化数据报对象
      DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length);
      // 接收消息
      server.receive(recvPacket);
      String recvStr = new String(recvPacket.getData(), 0,
            recvPacket.getLength());
      System.out.println("接收到消息:" + recvStr);
      int port = recvPacket.getPort();
      InetAddress addr = recvPacket.getAddress();
      String sendStr = "SUCCESS";
      byte[] sendBuf = sendStr.getBytes();

      // 创建回复数据报
      DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length,
            addr, port);
      // 发送回复
      server.send(sendPacket);
      server.close();
   }
}

客户端

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * UDP客户端
 * 
 * @author jianggujin
 * 
 */
public class UDPClient
{
   public static void main(String[] args) throws IOException
   {
      DatagramSocket client = new DatagramSocket();

      String sendStr = "HI!";
      byte[] sendBuf = sendStr.getBytes();
      // 接收消息的主机,255.255.255.255可广播给局域网内所有主机
      InetAddress addr = InetAddress.getByName("127.0.0.1");
      DatagramPacket sendPacket = new DatagramPacket(sendBuf, sendBuf.length,
            addr, 9999);
      // 发送数据包
      client.send(sendPacket);
      // 用于接收数据的缓冲数组
      byte[] recvBuf = new byte[100];
      // 实例化数据报对象
      DatagramPacket recvPacket = new DatagramPacket(recvBuf, recvBuf.length);
      // 接收消息
      client.receive(recvPacket);
      String recvStr = new String(recvPacket.getData(), 0,
            recvPacket.getLength());
      System.out.println("收到消息:" + recvStr);
      client.close();
   }
}

运行结果
服务端:
接收到消息:HI!

客户端:
收到消息:SUCCESS

目录
相关文章
|
5月前
|
JSON 移动开发 网络协议
Java网络编程:Socket通信与HTTP客户端
本文全面讲解Java网络编程,涵盖TCP与UDP协议区别、Socket编程、HTTP客户端开发及实战案例,助你掌握实时通信、文件传输、聊天应用等场景,附性能优化与面试高频问题解析。
|
3月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
228 1
|
3月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
243 1
|
3月前
|
机器学习/深度学习 分布式计算 Java
Java与图神经网络:构建企业级知识图谱与智能推理系统
图神经网络(GNN)作为处理非欧几里得数据的前沿技术,正成为企业知识管理和智能推理的核心引擎。本文深入探讨如何在Java生态中构建基于GNN的知识图谱系统,涵盖从图数据建模、GNN模型集成、分布式图计算到实时推理的全流程。通过具体的代码实现和架构设计,展示如何将先进的图神经网络技术融入传统Java企业应用,为构建下一代智能决策系统提供完整解决方案。
410 0
|
10月前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
455 23
|
11月前
|
网络协议 算法 安全
Go语言的网络编程与TCP_UDP
Go语言由Google开发,旨在简单、高效和可扩展。本文深入探讨Go语言的网络编程,涵盖TCP/UDP的基本概念、核心算法(如滑动窗口、流量控制等)、最佳实践及应用场景。通过代码示例展示了TCP和UDP的实现,并讨论了其在HTTP、DNS等协议中的应用。最后,总结了Go语言网络编程的未来发展趋势与挑战,推荐了相关工具和资源。
352 5
|
11月前
|
安全 网络协议 Java
Java网络编程封装
Java网络编程封装原理旨在隐藏底层通信细节,提供简洁、安全的高层接口。通过简化开发、提高安全性和增强可维护性,封装使开发者能更高效地进行网络应用开发。常见的封装层次包括套接字层(如Socket和ServerSocket类),以及更高层次的HTTP请求封装(如RestTemplate)。示例代码展示了如何使用RestTemplate简化HTTP请求的发送与处理,确保代码清晰易维护。
|
11月前
|
缓存 网络协议 Java
JAVA网络IO之NIO/BIO
本文介绍了Java网络编程的基础与历史演进,重点阐述了IO和Socket的概念。Java的IO分为设备和接口两部分,通过流、字节、字符等方式实现与外部的交互。
374 0
|
SQL 安全 网络安全
网络安全与信息安全:知识分享####
【10月更文挑战第21天】 随着数字化时代的快速发展,网络安全和信息安全已成为个人和企业不可忽视的关键问题。本文将探讨网络安全漏洞、加密技术以及安全意识的重要性,并提供一些实用的建议,帮助读者提高自身的网络安全防护能力。 ####
297 17
|
SQL 安全 网络安全
网络安全与信息安全:关于网络安全漏洞、加密技术、安全意识等方面的知识分享
随着互联网的普及,网络安全问题日益突出。本文将从网络安全漏洞、加密技术和安全意识三个方面进行探讨,旨在提高读者对网络安全的认识和防范能力。通过分析常见的网络安全漏洞,介绍加密技术的基本原理和应用,以及强调安全意识的重要性,帮助读者更好地保护自己的网络信息安全。
246 10