博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java网络编程——12.UDP
阅读量:6911 次
发布时间:2019-06-27

本文共 4704 字,大约阅读时间需要 15 分钟。

hot3.png

前面几章讨论了在TCP传输层协议之上运行的网络应用程序,TCP是为数据的可靠传输而设计的。用户数据报协议(User Datagram Protocal,UDP)是在IP之上发送数据的另一种传输层协议,速度很快,但不可靠。当发送UDP数据时,无法知道数据是否会到达,也不知道数据的各个部分是否会以发送时的顺序到达。

1、UDP协议

类似FTP的应用程序,需要通过网络进行可靠的数据传输,UDP不是一个好的选择。不过还有其他类型的应用程序,保持最快的速度比保证每一位数据都正确更为重要。例如在实时音频或视频中,丢失或交换数据包只是带来一些干扰而已。如果客户端像服务器发送一个短的UDP请求,倘若指定时间内没有响应返回,它会认为这个包已丢失。域名系统(Domain Name System,DNS)就采取这样的工作方式(也可以基于TCP)。用UDP也可以实现一个可靠的文件传输协议,如网络文件系统(Network File System,NFS)、简单FTP(Trivial FTP,TFTP)和FSP(与FTP关系比较远的一种协议)都使用了UDP。在这些协议中,由应用程序复杂可靠性,也就是说应用程序必须处理丢失或乱序的包。

TCP和UDP就像电话系统和邮局的关系。电话已接通,双方可以按顺序听到讲话。相反邮局寄包裹,接收方并不能保证按顺序收到邮件,而且有丢失的概率。电话系统和邮局都有各自的用处,尽管它们都是用来通信的,但在某些特定情况,二者之间肯定有优劣之分。UDP和TCP也是这样。TCP应用比UDP应用更常见,不过UDP也有自己的位置。本章我们将看到用UDP能做什么,进一步深入,下一章会介绍UDP之上的组播。组播socket是标准UDP socket的一种相当简单的变体。

Java中UDP的实现分为两个类:DatagramPacket和DatagramSocket。DatagramPacket类将数据自己填充到UDP包中,这称为数据报(datagram),由你来解包接收中的数据报。DatagramSocket可以收发UDP数据报。这种职责划分与TCP使用的Socket和ServerSocket有所不同,UDP没有两台主机之间唯一连接的概念。TCP socket把网络连接看作是流,UDP让你处理总是单个数据报包。

1、UDP客户端

先来看一个简单的例子,还是用第8章的例子,我们将连接daytime服务器,不过这次使用UDP而不是TCP:

import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.net.InetAddress;public class UDPClient {    public static void main(String[] args) {        try (DatagramSocket socket = new DatagramSocket(0)) {            socket.setSoTimeout(10000);// 超时时间很重要            InetAddress host = InetAddress.getByName("121.40.47.132");            DatagramPacket request = new DatagramPacket(new byte[1], 1, host, 13);            DatagramPacket response = new DatagramPacket(new byte[1024], 1024);// 分配1KB的空间            socket.send(request);            socket.receive(response);            String result = new String(response.getData(), 0, response.getLength());            System.out.println(result);        } catch (IOException e) {            e.printStackTrace();        }    }}

2、UDP服务器

UDP服务器几乎遵循与UDP客户端同样的模式,只不过通常在发送之前会接收,而且不会选择要绑定的匿名端口。

import java.io.IOException;import java.net.DatagramPacket;import java.net.DatagramSocket;import java.util.Date;import org.slf4j.Logger;import org.slf4j.LoggerFactory;public class DayTimeUDPServer {    private static final Logger logger = LoggerFactory.getLogger(DayTimeUDPServer.class.getCanonicalName());    public static void main(String[] args) {        try (DatagramSocket socket = new DatagramSocket(13)) {            while (true) {                try {                    DatagramPacket request = new DatagramPacket(new byte[1024], 1024);                    socket.receive(request);                    String daytime = new Date().toString();                    byte[] data = daytime.getBytes();                    DatagramPacket response = new DatagramPacket(data, data.length, request.getAddress(),                            request.getPort());                    socket.send(response);                    logger.info(daytime + " " + request.getAddress());                } catch (IOException | RuntimeException e) {                    logger.error("", e);                }            }        } catch (Exception e) {            logger.error("", e);        }    }}

从这个例子可以看出,UDP服务器往往不是多线程的,它们通常不会对某一个客户做太多工作,而且不会阻塞来等待另一端的响应,因为UDP从来不会报告错误。

3、DatagramPacket类

UDP数据报是基于IP数据报建立的,只向其底层IP数据报添加了很少的一点内容。

UDP数据报结构

很多平台限制UDP包中的数据8192字节(8KB),多余的会被截取。为保证最大的安全性,UDP包的数据部分应当保持为512字节或更少。TCP数据报也存在这个问题,但Socket和ServerSocket提供的是基于流的API,对程序员隐藏了这些细节。

在Java中,UDP数据报用DatagramPacket类的实例表示,这个类提供了一些方法来获取和设置IP首部中的源或目标地址、获取和设置源或目标端口、获取和设置数据,以及获取和设置数据长度。其余首部字段无法通过纯Java代码访问。

4、DatagramSocket类

要收发DatagramPacket,必须打开一个数据报Socket,在Java中,数据报Socket通过DatagramSocket类创建和访问。客户端和服务器使用的Socket是一样的,区别只在于使用匿名端口(系统分配的端口)还是已知端口。与TCP中不同,不存在诸如DatagramServerSocket之类的东西。

Java支持6个UDP Socket选项:

  • SO_TIMEOUT:receive()在抛出IngterruptIOException异常前等待入站数据报的时间,serSoTimeout()方法可以改变这个值。
  • SO_RCVBUF:确定了用于网络I/O的缓冲区大小。setReceiveBufferSize()方法会建议对来自这个Socket的输入进行缓冲时使用的字节数,依赖于平台的限制。
  • SO_SNDBUF:用于网络输出的发送缓冲区大小,setSendBufferSize()。
  • SO_REUSEADDR:控制是否允许多个数据报Socket同时绑定到相同的端口和地址。
  • SO_BROADCAST:控制是否允许一个Socket向广播地址收发包。
  • IP_TOS:业务流类型由各个IP数据报首部中的IP_TOS字段值来确定,所以它对于UDP与TCP一样重要。DatagramSocket中的setTrafficClass()和getTrafficClass()方法与Socket中的相应方法实际上没有分别。业务流类型用0到255之间的整数指定,详细请参考“IP_TOS服务类型”相关知识。

5、一些有用的应用程序

UDP客户端:一些Internet服务只需要知道客户端的地址和端口,它们会忽略客户端在数据报中发送的数据。因此可以向服务器发送一个UDP数据报,读取传回的响应。

UDP服务端:如echo服务器,你可以在一台机器上运行echo客户端,来验证两台机器之间的网络是否正常。

6、DatagramChannel

DatagramChannel类用于非阻塞UDP应用程序,就像SocketChannel和ServerSocketChannel用于非阻塞TCP应用程序一样。不过,UDP天生就比TCP更具异步性,因而实际效果没有那么明显,在UDP中,一个数据报Socket可以处理多个客户端的输入和输出请求,DatagramChannel类所增加的就是能够以非阻塞方式来做到这一点,这样一来,如果网络没有立即准备好收发数据,这些方法可以迅速返回。

对于UDP,DatagramChannel是一个近乎完备的候选API,在Java 6及之前版本中,仍需使用DatagramSocket类将通道绑定一个端口。不过在Java 7及以后版本中就不一定非得使用这个类了,也不必使用DatagramPacket,读/写字节缓冲区,就像对SocketChannel的操作一样。

转载于:https://my.oschina.net/zhaoyi1/blog/893545

你可能感兴趣的文章
[Head First设计模式]策略模式
查看>>
阿里云ECS服务器源配置
查看>>
github插件
查看>>
iOS重绘机制drawRect
查看>>
Elementary Methods in Number Theory Exercise 1.2.4
查看>>
Spring+Ehcache
查看>>
winform:界面加载时自定义选中Button
查看>>
第四周总结
查看>>
maven-surefire-plugin:jar:2.12.4 has not been downloaded from it before.
查看>>
PXE 自动安装物理机 (DHCP服务由路由提供, 不能再配置)
查看>>
Python中的单例模式
查看>>
Android开发基础知识
查看>>
Ubuntu的快捷键
查看>>
视频压缩编码问答--转载
查看>>
android ListView中使用notifyDataSetChanged()不刷新
查看>>
Sandcastle入门:创建C#帮助文档
查看>>
[bzoj 4036][HAOI2015]按位或
查看>>
Django的ModelForm
查看>>
C++对象指针—指向对象成员的指针
查看>>
supermap使用小结
查看>>