UDP 协议提供了一种不同于 TCP协议的端到端服务,实际上 UDP 协议只实现两个功能:
1)在 IP协议的基础上添加了另一层地址(端口)
2)对数据传输过程中可能产生的数据错误进行了检测,并抛弃已经损坏的数据。
TCP与UDP协议的异同:
1) UDP 套接字在使用前不需要进行连接,但必须指定目的地址。每组报文负载了自己的地址信息,并与其他信息相互独立。在接受信息时,UDP套接字扮演的角色像是一个邮箱,从不同地址发送来的信件和包裹都可以放到里面。一旦被创建,UDP 套接字就可以用来连续地向不同的地址发送信息,或从任何地址接收信息。
2) UDP套接字将保留边界信息。,
3) UDP 协议所提供的端到端传输服务是尽力而为(best-effort)的,即 UDP 套接字将尽可能地传送信息,但并不保证信息一定能成功到达目的地址,而且信息到达的顺序与其发送顺序不一定一致。
Java 程序员通过 DatagramPacket 类和 DatagramSocket 类来使用 UDP 套接字,客户端和服务器端都使用 DatagramSockets来发送数据,使用 DatagramPackets来接收数据。
DatagramPacket类
与 TCP协议发送和接收字节流不同,UDP 终端交换的是一种称为数据报文的自包含(self-contained)信息。
这种信息在 Java 中表示为 DatagramPacket 类的实例。发送信息时,Java 程序创建一个包含了待发送信息的 DatagramPacket 实例,并将其作为参数传递给DatagramSocket 类的 send()方法。
接收信息时, Java程序首先创建一个 DatagramPacket 实例,该实例中预先分配了一些空间,并将接收到的信息存放在该空间中。然后把该实例作为参数传递给 DatagramSocket 类的 receive()方法。
每个 DatagramPacket 实例中还附加了地址和端口信息,其具体含义取决于该数据报文是被发送还是被接收。若是要发送的数据报文, DatagramPacket 实例中的地址则指明了目的地址和端口号,若是接收到的数据报文, DatagramPacket实例中的地址则指明了所收信息的源地址。因此,服务器端可以修改接收到的 DatagramPacket 实例的缓存区内容,再将这个实例连同修改后的信息一起,发回给它的源地址。
DatagramPacket: 创建
DatagramPacket(byte[ ] data, int length)
DatagramPacket(byte[ ] data, int offset, int length)
DatagramPacket(byte[ ] data, int length, InetAddress remoteAddr, int remotePort)
DatagramPacket(byte[ ] data, int offset, int length, InetAddress remoteAddr, int remotePort)
DatagramPacket(byte[ ] data, int length, SocketAddress sockAddr)
DatagramPacket(byte[ ] data, int offset, int length, SocketAddress sockAddr)
如果指定了 offset,数据报文的数据部分将从字节数组的指定位置发送或接收数据,length 参数指定了字节数组中在发送时要传输的字节数,或在接收数据时所能接收的最多字节数。
DatagramPacket: 地址处理
InetAddress getAddress()
void setAddress(InetAddress address)
int getPort()
void setPort(int port)
SocketAddress getSocketAddress()
void setSocketAddress(SocketAddress sockAddr)
DatagramSocket 的 receive()方法是将其地址和端口设置为数据报发送者的地址和端口。
DatagramPacket: 处理数据
int getLength() //返回数据长度
void setLength(int length) //设置数据内部长度
int getOffset() //返回发送或接收的数据存放在缓存区时的偏移量
byte[ ] getData()
void setData(byte[ ] data)
void setData(byte[ ] buffer, int offset, int length)
getData()方法返回与数据报文相关联的字节数组,实际返回的是对与 DatagramPacket最近关联的字节数组的一个引用,而关联则是通过构造函数或 setData()方法形成。
返回的缓存数组的长度可能比数据报文内部长度更长,因此,必须使用内部长度和偏移量来指定实际接收到的信息。
setData()方法指定一个字节数组作为该数据报文的数据部分,第一种形式将整个字节数组作为缓冲区,第二种形式把字节数组中,从 offset 到 offset+length-1 的部分作为缓存区,每次调用第二种形式的 setData()方法,都将更新数据的内部偏移量和长度。