基于UDP的Socket通信

基于UDP的Socket通信

注意,在使用UDP实现Socket通信时一定要使用两台真机,不要使用虚拟机,不然会出现UDP包无法发送的情况。

UDP ( User Datagram Protocol,用户数据报协议)是-种面向无连接的传输层协议,提供不可靠的信息传送服务。
无连接是指通信时服务端与客户端不需要建立连接,直接把数据包从一端发送到另一端,对方获取数据包再进行数据的处理。

UDP是“不可靠的”,是指该协议在网络环境不好的情况下,会丢失数据包,因为没有数据包重传的功能,另外它也不提供对数据包进行分组、组装,以及不能对数据包进行排序,这些都是它和TCP最主要的区别。使用UDP发送报文后,是无法得知其是否安全,以及是否完整地到达目的地的。

UDP将网络数据流量压缩成数据包的形式,一个典型的数据包就是一个二进制的数据传输单位,每一个数据包的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
因为UDP报文没有可靠性保证、没有顺序保证,以及没有流量控制等功能,所以它可靠性较差。但是,正因为UDP的控制选项较少,在数据传输过程中延迟小、数据传输效率高,因而适合对可靠性要求不高的应用程序。
UDP和TCP都属于传输层协议。

在选择使用某种协议的时候,选择UDP必须要谨慎,因为在网络质量不好的情况下,UDP的数据包丟失的情况会比较严重,但正是因为它是无连接型协议,因而具有资源消耗小、处理速度快的优点。通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一-两个数据包,也不会对接收结果产生太大影响,如视频聊天时,丟失某些帧对聊天效果影响不大。

TCP中包含了专门的传递保证机制,来确保发送的数据能到达对端,并且是有序的。UDP与TCP不同,UDP并不提供数据传送的保证机制,如果在从发送方到接收方的传递过程中出现数据报的丢失,协议本身并不能做出任何检测或提示,因此,经常把UDP称为不可靠的传输协议。

另外,相对于TCP,UDP的另外一个不同之处是不能确保数据的发送和接收的顺序。

使用UDP实现Socket通信

在使用UDP实现Socket通信时,服务端与客户端都是使用DatagramSocket类,传输的数据要存放在DatagramPacket类中。

DatagramSocket类表示用来发送和接收数据报包的套接字。数据报套接字是包投递服务的发送或接收点。每个在数据报套接字上发送或接收的包都是单独编址和路由的。从一台机器发送到另一台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。在DatagramSocket.上总是启用UDP广播发送。为了接收广播包,应该将DatagramSocket绑定到通配符地址。在某些实现中,将DatagramSocket绑定到一个更加具体的地址时广播包也可以被接收。

DatagramSocket s = new DatagramSocket(null);
s.bind(new InetSocketAddress(8888));
//等价于
DatagramSocket s = new DatagramSocket(8888);

DatagramPacket类表示数据报包。数据报包用来实现无连接包投递服务。每条报文仅根据该包中包含的信息从一台机器路由到另一台机器。从一台机器发送到另- -台机器的多个包可能选择不同的路由,也可能按不同的顺序到达。

DatagramSocket类中的public synchronized void receive(DatagramPacket p)方法的作用是从此套接字接收数据报包。当此方法返回时,DatagramPacket 的缓冲区填充了接收的数据。数据报包也包含发送方的IP地址和发送方机器上的端口号。此方法在接收到数据报前一直阻塞。数据报包对象的length字段包含所接收信息的长度。如果发送的信息比接收端包关联的byte[]长度长,该信息将被截短。如果发送信息的长度大于65507,则发送端出现异常。

DatagramSocket类中的public void send(DatagramPacket p)方法的作用是从此套接字发送数据报包。DatagramPacket 包含的信息有:将要发送的数据及其长度、远程主机的IP地址和远程主机的端口号。

DatagramPacket类中的public synchronized byte[] getData()方法的作用是返回数据缓冲区。接收到的或将要发送的数据从缓冲区中的偏移量offset处开始,持续length长度。

本测试要实现的是客户端使用UDP将字符串1234567890传递到服务端。

public static void main(String[] args) {
        try {
            DatagramSocket socket = new DatagramSocket(8888);
            byte[] byteArray = new byte[12];
            //构造方法第二个参数也要写上10个,代表要接收数据的长度为10
            //和客户端发送数据的长度一致
            DatagramPacket myPacket = new DatagramPacket(byteArray, 10);
            socket.receive(myPacket);
            socket.close();
            System.out.println("包中数据的长度:" + myPacket.getLength());
            System.out.println(new String(myPacket.getData(), 0, myPacket.getLength()));
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

public static void main(String[] args) {
        //客户端要发送的数据字节长度为10
        //所以服务端只能最大取得10个数据
        try {
            DatagramSocket socket = new DatagramSocket();
            socket.bind(new InetSocketAddress("localhost", 8888));
            byte[] byteArray = "1234567890".getBytes();
            DatagramPacket myPacket = new DatagramPacket(byteArray, byteArray.length);
            socket.send(myPacket);
            socket.close();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
发送超大数据量的包导致数据截断的情况

理论上,一个UDP包最大的长度为216-1 (65536- 1=65535),因此,IP 包最大的发送长度为65535。但是,在这65535之内包含IP协议头的20个字节,还有UDP协议头的.8个字节,即65535 - 20- 8= 65507,因此,UDP传输用户数据最大的长度为65507。如果传输的数据大于65507,则在发送端出现异常。

Datagram Packet类中常用API的使用

DatagramPacket类中的public synchronized void setData(byte[] buf)方法的作用是为此包设置数据缓冲区。将此DatagramPacket的偏移量设置为0,长度设置为buf的长度。

DatagramPacket类中的public synchronized void setData(byte[] buf, int offset, int length)方法的作用是为此包设置数据缓冲区。此方法设置包的数据、长度和偏移量。

DatagramPacket类中的public synchronized int getOffset()方法的作用是返回将要发送或接收到的数据的偏移量。

DatagramPacket类中的public synchronized void setLength(int length)方法的作用是为此包设置长度。包的长度是指包数据缓冲区中将要发送的字节数,或用来接收数据的包数据缓冲区的字节数。长度必须小于或等于偏移量与包缓冲区长度之和。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值