- DatagramSocket 類
- DatagramPacket 類
- 案例:文件上傳工具
??UDP 就像日常生活中的郵件投遞,不能保證可靠地寄到目的地。UDP 是無連接的,對系統(tǒng)資源的要求較少,UDP 可能丟包且不保證數(shù)據(jù)順序俏讹。但是對于網(wǎng)絡(luò)游戲和在線視頻等要求傳輸快、實時性高挽荡、質(zhì)量可稍差一點的數(shù)據(jù)傳輸藐石,UDP 還是非常不錯的。
??UDP Socket 網(wǎng)絡(luò)編程比 TCP Socket 編程簡單得多定拟,UDP 是無連接協(xié)議,不需要像 TCP 一樣監(jiān)聽端口且建立連接,才能進(jìn)行通信青自。
一株依、DatagramSocket 類
??java.net
包中提供了兩個類 DatagramSocket
和 DatagramPacker
,用來支持 UDP 通信延窜。DatagramSocket
用于在程序之間建立傳送數(shù)據(jù)報的通信連接恋腕。
下面是 DatagramSocket 常用的構(gòu)造函數(shù):
-
DatagramSocket()
。創(chuàng)建數(shù)據(jù)報 DatagramSocket 對象逆瑞,并將其綁定到本地主機(jī)上任何可以的端口荠藤。 -
DatagramSocket(port: Int)
。創(chuàng)建數(shù)據(jù)報 DatagramSocket 對象获高,并將其綁定到本地主機(jī)上的指定端口哈肖。 -
DatagramSocket(port: Int, laddr: InetAddress!)
。創(chuàng)建數(shù)據(jù)報 DatagramSocket 對象念秧,并將其綁定到指定的本地地址淤井。
DatagramSocket 其他的常用函數(shù)和屬性有:
-
send(p: DatagramPacket!)
。發(fā)送數(shù)據(jù)報包摊趾。 -
receive(p: DatagramPacket!)
币狠。接收數(shù)據(jù)報包。 -
port
屬性砾层。返回 DatagramSocket 連接到的遠(yuǎn)程端口漩绵。 -
localPort
。返回 DatagramSocket 綁定到的本地端口肛炮。 -
inetAddress
屬性:返回 DatagramSocket 連接地址止吐。 -
localAddress
屬性:返回 DatagramSocket 綁定的本地地址。 -
isClosed
屬性:判斷返回 DatagramSocket 是否處于關(guān)閉狀態(tài)铸董。 -
isConnected
屬性:判斷返回 DatagramSocket 是否處于連接狀態(tài)祟印。 -
close()
函數(shù):關(guān)閉 DatagramSocket。
??DatagramSocket 也實現(xiàn)了 AutoCloseable
接口粟害,可以通過自動資源管理技術(shù)關(guān)閉 DatagramSocket蕴忆。
二、DatagramPacket 類
??DatagramPacket 用來表示數(shù)據(jù)報包悲幅,是數(shù)據(jù)傳輸?shù)妮d體套鹅。
下面是 DatagramPacket 的構(gòu)造函數(shù):
-
DatagramPacket(buf: ByteArray!, length: Int)
。構(gòu)造數(shù)據(jù)報包汰具,其中 buf 是包數(shù)據(jù)卓鹿,length 是接收包數(shù)據(jù)的長度。 -
DatagramPacket(buf: ByteArray!, length: Int, address: InetAddress!, port: Int)
留荔。構(gòu)造數(shù)據(jù)報包吟孙,包發(fā)送到指定主機(jī)上的指定端口號。 -
DatagramPacket(buf: ByteArray!, offset: Int, length: Int)
。構(gòu)造數(shù)據(jù)報包杰妓,其中 offset 是 buf 字節(jié)數(shù)組的偏移量藻治。 -
DatagramPacket(buf: ByteArray!, offset: Int, length: Int, address: InetAddress!, port: Int)
。構(gòu)造數(shù)據(jù)報包巷挥,包發(fā)送到指定主機(jī)上的指定端口號桩卵。
DatagramPacket 常用屬性如下:
-
address
。返回發(fā)往或接收該數(shù)據(jù)報包相關(guān)的主機(jī) IP 地址倍宾,屬性類型是 InetAddress雏节。 -
data
。返回數(shù)據(jù)報包中的數(shù)據(jù)高职,屬性類型是 ByteArray钩乍。 -
length
。返回發(fā)送或接收到數(shù)據(jù)的長度初厚,屬性類型是 Int件蚕。 -
offset
。返回發(fā)送或接收到的數(shù)據(jù)的偏移量产禾,屬性類型是 Int排作。 -
port
。返回發(fā)送或接收該數(shù)據(jù)報包相關(guān)的主機(jī)的端口號亚情,屬性類型是 Int妄痪。
三、案例:文件上傳工具
- 案例服務(wù)器端 UploadServer 代碼:
fun main(args: Array<String>) {
println("服務(wù)器端運行...")
startServer()
}
fun startServer() {
DatagramSocket(8080).use { socket ->
FileOutputStream("./TestDir/subDir/src.zip").use { fos ->
BufferedOutputStream(fos).use { bos ->
// 準(zhǔn)備一個緩沖區(qū)
val buffer = ByteArray(1024)
// 循環(huán)接收數(shù)據(jù)報包
while (true) {
// 創(chuàng)建數(shù)據(jù)報包對象楞件,用來接收數(shù)據(jù)
val packet = DatagramPacket(buffer, buffer.size)
// 接收數(shù)據(jù)報包
socket.receive(packet)
// 接收數(shù)據(jù)長度
val len = packet.length
if (len == 3) {
// 獲得結(jié)束標(biāo)志
val flag = String(buffer, 0, 3)
// 判斷結(jié)束標(biāo)志衫生,如果是bye則結(jié)束接收。
if (flag == "bye") {
break
}
}
// 寫入數(shù)據(jù)到文件輸出流
bos.write(buffer, 0, len)
}
println("接收完成土浸!")
}
}
}
}
??與 TCP Socket 不同罪针,UDP Socket 無法知道哪些數(shù)據(jù)包是最后一個,因此需要發(fā)送方發(fā)出一個特殊的數(shù)據(jù)包黄伊,包中包含了一些特殊標(biāo)志泪酱。
- 案例客戶端 UploadClient 代碼:
fun main(args: Array<String>) {
println("客戶端運行...")
startClient()
}
fun startClient() {
DatagramSocket().use { socket ->
FileInputStream("./TestDir/src.zip").use { fis ->
BufferedInputStream(fis).use { input ->
// 創(chuàng)建遠(yuǎn)程主機(jī) IP 地址對象
val address = InetAddress.getByName("localhost")
// 準(zhǔn)備一個緩沖區(qū)
val buffer = ByteArray(1024)
// 首次從文件流中讀取數(shù)據(jù)
var len = input.read(buffer)
while (len != -1) {
// 創(chuàng)建數(shù)據(jù)報包對象
val packet = DatagramPacket(buffer, len, address, 8080)
// 發(fā)送數(shù)據(jù)報包
socket.send(packet)
// 再次從文件流中讀取數(shù)據(jù)
len = input.read(buffer)
}
// 創(chuàng)建數(shù)據(jù)報對象, 一個結(jié)束上傳的數(shù)據(jù)報包
val packet = DatagramPacket("bye".toByteArray(), 3, address, 8080)
socket.send(packet)
println("上傳完成!")
}
}
}
}