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

上一篇:arcgis开发笔记【参考资料】


下一篇:day27_Struts2学习笔记_04