Kotlin网络编程(4)UDP Socket 低层次网络编程

2019-07-03  本文已影响0人  狼性代码人
  • DatagramSocket 类
  • DatagramPacket 类
  • 案例:文件上传工具

  UDP 就像日常生活中的邮件投递,不能保证可靠地寄到目的地。UDP 是无连接的,对系统资源的要求较少,UDP 可能丢包且不保证数据顺序。但是对于网络游戏和在线视频等要求传输快、实时性高、质量可稍差一点的数据传输,UDP 还是非常不错的。

  UDP Socket 网络编程比 TCP Socket 编程简单得多,UDP 是无连接协议,不需要像 TCP 一样监听端口且建立连接,才能进行通信。

一、DatagramSocket 类

  java.net 包中提供了两个类 DatagramSocketDatagramPacker,用来支持 UDP 通信。DatagramSocket 用于在程序之间建立传送数据报的通信连接。

下面是 DatagramSocket 常用的构造函数:

DatagramSocket 其他的常用函数和属性有:

  DatagramSocket 也实现了 AutoCloseable 接口,可以通过自动资源管理技术关闭 DatagramSocket。

二、DatagramPacket 类

  DatagramPacket 用来表示数据报包,是数据传输的载体。

下面是 DatagramPacket 的构造函数:

DatagramPacket 常用属性如下:

三、案例:文件上传工具

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 无法知道哪些数据包是最后一个,因此需要发送方发出一个特殊的数据包,包中包含了一些特殊标志。

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("上传完成!")
            }
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读