- DatagramSocket 类
- DatagramPacket 类
- 案例:文件上传工具
UDP 就像日常生活中的邮件投递,不能保证可靠地寄到目的地。UDP 是无连接的,对系统资源的要求较少,UDP 可能丢包且不保证数据顺序。但是对于网络游戏和在线视频等要求传输快、实时性高、质量可稍差一点的数据传输,UDP 还是非常不错的。
UDP Socket 网络编程比 TCP Socket 编程简单得多,UDP 是无连接协议,不需要像 TCP 一样监听端口且建立连接,才能进行通信。
一、DatagramSocket 类
java.net
包中提供了两个类 DatagramSocket
和 DatagramPacker
,用来支持 UDP 通信。DatagramSocket
用于在程序之间建立传送数据报的通信连接。
下面是 DatagramSocket 常用的构造函数:
-
DatagramSocket()
。创建数据报 DatagramSocket 对象,并将其绑定到本地主机上任何可以的端口。 -
DatagramSocket(port: Int)
。创建数据报 DatagramSocket 对象,并将其绑定到本地主机上的指定端口。 -
DatagramSocket(port: Int, laddr: InetAddress!)
。创建数据报 DatagramSocket 对象,并将其绑定到指定的本地地址。
DatagramSocket 其他的常用函数和属性有:
-
send(p: DatagramPacket!)
。发送数据报包。 -
receive(p: DatagramPacket!)
。接收数据报包。 -
port
属性。返回 DatagramSocket 连接到的远程端口。 -
localPort
。返回 DatagramSocket 绑定到的本地端口。 -
inetAddress
属性:返回 DatagramSocket 连接地址。 -
localAddress
属性:返回 DatagramSocket 绑定的本地地址。 -
isClosed
属性:判断返回 DatagramSocket 是否处于关闭状态。 -
isConnected
属性:判断返回 DatagramSocket 是否处于连接状态。 -
close()
函数:关闭 DatagramSocket。
DatagramSocket 也实现了 AutoCloseable
接口,可以通过自动资源管理技术关闭 DatagramSocket。
二、DatagramPacket 类
DatagramPacket 用来表示数据报包,是数据传输的载体。
下面是 DatagramPacket 的构造函数:
-
DatagramPacket(buf: ByteArray!, length: Int)
。构造数据报包,其中 buf 是包数据,length 是接收包数据的长度。 -
DatagramPacket(buf: ByteArray!, length: Int, address: InetAddress!, port: Int)
。构造数据报包,包发送到指定主机上的指定端口号。 -
DatagramPacket(buf: ByteArray!, offset: Int, length: Int)
。构造数据报包,其中 offset 是 buf 字节数组的偏移量。 -
DatagramPacket(buf: ByteArray!, offset: Int, length: Int, address: InetAddress!, port: Int)
。构造数据报包,包发送到指定主机上的指定端口号。
DatagramPacket 常用属性如下:
-
address
。返回发往或接收该数据报包相关的主机 IP 地址,属性类型是 InetAddress。 -
data
。返回数据报包中的数据,属性类型是 ByteArray。 -
length
。返回发送或接收到数据的长度,属性类型是 Int。 -
offset
。返回发送或接收到的数据的偏移量,属性类型是 Int。 -
port
。返回发送或接收该数据报包相关的主机的端口号,属性类型是 Int。
三、案例:文件上传工具
- 案例服务器端 UploadServer 代码:
fun main(args: Array<String>) {
println("服务器端运行...")
startServer()
}
fun startServer() {
DatagramSocket(8080).use { socket ->
FileOutputStream("./TestDir/subDir/src.zip").use { fos ->
BufferedOutputStream(fos).use { bos ->
// 准备一个缓冲区
val buffer = ByteArray(1024)
// 循环接收数据报包
while (true) {
// 创建数据报包对象,用来接收数据
val packet = DatagramPacket(buffer, buffer.size)
// 接收数据报包
socket.receive(packet)
// 接收数据长度
val len = packet.length
if (len == 3) {
// 获得结束标志
val flag = String(buffer, 0, 3)
// 判断结束标志,如果是bye则结束接收。
if (flag == "bye") {
break
}
}
// 写入数据到文件输出流
bos.write(buffer, 0, len)
}
println("接收完成!")
}
}
}
}
与 TCP Socket 不同,UDP Socket 无法知道哪些数据包是最后一个,因此需要发送方发出一个特殊的数据包,包中包含了一些特殊标志。
- 案例客户端 UploadClient 代码:
fun main(args: Array<String>) {
println("客户端运行...")
startClient()
}
fun startClient() {
DatagramSocket().use { socket ->
FileInputStream("./TestDir/src.zip").use { fis ->
BufferedInputStream(fis).use { input ->
// 创建远程主机 IP 地址对象
val address = InetAddress.getByName("localhost")
// 准备一个缓冲区
val buffer = ByteArray(1024)
// 首次从文件流中读取数据
var len = input.read(buffer)
while (len != -1) {
// 创建数据报包对象
val packet = DatagramPacket(buffer, len, address, 8080)
// 发送数据报包
socket.send(packet)
// 再次从文件流中读取数据
len = input.read(buffer)
}
// 创建数据报对象, 一个结束上传的数据报包
val packet = DatagramPacket("bye".toByteArray(), 3, address, 8080)
socket.send(packet)
println("上传完成!")
}
}
}
}
网友评论