Java网络编程——12.UDP

Wesley13
• 阅读 712

前面几章讨论了在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数据报添加了很少的一点内容。

Java网络编程——12.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的操作一样。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
网络
文章目录深入理解TCP/IP协议1、TCP/IP协议的概念2、TCP/IP的分层管理1\.物理层2\.数据链路层MAC地址广播3\.网络层IP协议4\.传输层UDP协议TCP协议5\.应用层(会
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
MQTT,CoAP,,LWM2M,UDP,TCP各自特点,NB
UDP用户数据报协议(UDP,UserDatagramProtocol)传输层协议1.是无连接的,即发送数据之前不需要建立连接。2.尽最大努力交付,即不保证可靠交付3.传输效率高,适用于对高速传输和实时性有较高的通信或广播通信。4.支持一对一,一对多,多对一和多对多的交互通信。TCP传输控制协议(TCP,Transmis
Wesley13 Wesley13
3年前
34.TCP取样器
阅读文本大概需要3分钟。1、TCP取样器的作用   TCP取样器作用就是通过TCP/IP协议来连接服务器,然后发送数据和接收数据。2、TCP取样器详解!(https://oscimg.oschina.net/oscnet/32a9b19ba1db00f321d22a0f33bcfb68a0d.png)TCPClien
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这