文档章节

Java网络编程——12.UDP

天子剑毅
 天子剑毅
发布于 2017/05/05 17:37
字数 1849
阅读 65
收藏 1
UDP

前面几章讨论了在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的操作一样。

© 著作权归作者所有

天子剑毅
粉丝 2
博文 34
码字总数 40324
作品 0
杭州
架构师
私信 提问
JVM救不了Java (转载)

面临应用程序网络化的发展趋势,我认为Java由于其设计架构上的弊端,在网站开发上将很难有大的作为。与此相反,以PHP为代表的动态语言则天生就适合网络的开发模式。 ——Zend公司CTO Andi Gu...

晨曦之光
2012/04/10
182
0
JAVA基础再回首(三十)——JAVA基础再回首完美结束,感概万千!

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/m366917/article/details/52724939 JAVA基础再回首(三十)——JAVA基础再回首完美结束,感概万千! 经过了几...

Aduroidpc
2016/10/02
0
0
Vert.x中国用户组(上海地区)第一次技术沙龙

导读 是否还在羡慕node.js程序员秀事件驱动编程?Golang程序员秀coroutine? Java8内置了Lambda表达式,函数式编程,全新异步API等全新功能,但是否还是觉得无法在传统的Java项目有用武之地?...

力谱宿云
2016/07/04
384
1
Java:过去、未来的互联网编程之王

Java对你而言是什么?一门你大学里学过的语言?一个IT行业的通用语言?你相信Java已经为下一次互联网爆炸做好了准备么?Java 一方面为嵌入式计算做了增强,而另一方面为实时应用做了精简,本...

oschina
2015/08/01
6.3K
33
java 7 入门书籍

一、Java从入门到精通 《Java从入门到精通(第3版)》从初学者角度出发,通过通俗易懂的语言、丰富多彩的实例,详细介绍了使用Java语言进行程序开发需要掌握的知识。 《Java从入门到精通(第3版...

modernizr
2014/05/15
6.9K
9

没有更多内容

加载失败,请刷新页面

加载更多

spring 本类中方法调用另外一个方法事务不生效

1、在spring配置文件中添加 <aop:aspectj-autoproxy expose-proxy="true"/> 声明自动代理 2、AopContext.currentProxy()来获取代理类 3、使用代理类proxy进行代理调用内部声明了事务的方法 ......

重城重楼
29分钟前
5
0
项目 banner 乱弹

------------------------------------------ 村上春树 ------------------------------------- 如果我爱你,而你也正巧爱我,你头发乱了的时候,我会笑笑地替你拨一拨,然后手还留恋地在你...

宿小帅
41分钟前
3
0
PHP获取未来七天的日期和星期

php获取未来七天的日期和星期代码 第一步:获取需要天数的日期,然后调用函数 //获取未来七天的日期 for($i=1;$i<8;$i++){ $dateArray[$i]=date('Y-m-d',strtotime(d...

一只懒猫-
53分钟前
2
0
总结:IO模型

分类 多路复用 参考文章: https://www.jianshu.com/p/6a6845464770 https://www.cnblogs.com/zingp/p/6863170.html https://blog.csdn.net/sehanlingfeng/article/details/78920423......

浮躁的码农
56分钟前
2
0
fabric-sdk-java 1.4安装说明

Hyperledger Fabric Java SDK是开发基于Hyperledger Fabric区块链的Java应用之必备开发包。本文将介绍如何在Maven、Gradle和Eclipse中安装使用最新1.4版本的Hyperledger Fabric Java SDK。 ...

汇智网教程
57分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部