TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据。相对TCP,UDP则是面向无连接的协议。
使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号,就可以直接发数据包。但是,能不能到达就不知道了。
虽然用UDP传输数据不可靠,但它的优点是和TCP比,速度快,对于不要求可靠到达的数据,就可以使用UDP协议。
一、UDP的概述(User Datagram Protocol,用户数据报协议)
UDP是传输层的协议,功能即为在IP的数据报服务之上增加了最基本的服务:
复用和分用以及差错检测。
UDP提供不可靠服务,具有TCP所没有的优势:
- UDP无连接,时间上不存在建立连接需要的时延。空间上,TCP需要在端系统中维护连接状态,需要一定的开销。
DNS如果运行在TCP之上而不是UDP,那么DNS的速度将会慢很多。
HTTP使用TCP而不是UDP,是因为对于基于文本数据的Web网页来说,可靠性很重要。
- 分组首部开销小**,TCP首部20字节,UDP首部8字节。
- UDP没有拥塞控制,应用层能够更好的控制要发送的数据和发送时间,网络中的拥塞控制也不会影响主机的发送速率。某些实时应用要求以稳定的速度发送,能容 忍一些数据的丢失,但是不能允许有较大的时延 (比如实时视频,直播等)
- UDP提供尽最大努力的交付,不保证可靠交付。
- UDP是面向报文的
对应用层交下来的报文,添加首部后直接乡下交付为IP层,既不合并,也不拆分,保留这些报文的边界。对IP层交上来UDP用户数据报,在去除首部后就原封不动地交付给上层应用进程,报文不可分割,是UDP数据报处理的最小单位。
- UDP常用一次性传输比较少量数据的网络应用,如DNS,SNMP等
因为对于这些应用,若是采用TCP,为连接的创建,维护和拆除带来不小的开销。UDP也常用于多媒体应用(如IP电话,实时视频会议,流媒体等)数据的可靠传输对他们而言并不重要,TCP的拥塞控制会使他们有较大的延迟,也是不可容忍的
二、UDP的首部格式
UDP数据报分为首部和用户数据部分
,整个UDP数据报作为IP数据报的数据部分封装在IP数据报中,UDP数据报文结构如图所示:
UDP首部有8个字节,由4个字段构成,每个字段都是两个字节,
源端口
: 源端口号,需要对方回信时选用,不需要时全部置0.目的端口
: 目的端口号,在终点交付报文的时候需要用到。长度
: UDP的数据报的长度(包括首部和数据)其最小值为8(只有首部)校验和
: 检测UDP数据报在传输中是否有错,有错则丢弃。(该字段是可选的)
当传输层从IP层收到UDP数据报时,就根据首部中的目的端口,把UDP数据报通过相应的端口,上交给应用进程。
如果接收方UDP发现收到的报文中的目的端口号不正确(不存在对应端口号的应用进程0,),就丢弃该报文,并由ICMP发送“端口不可达”差错报文给对方。
UDP 特性
- UDP 缺乏可靠性。UDP 本身不提供确认,序列号,超时重传等机制。UDP 数据报可能在网络中被复制,被重新排序。即 UDP 不保证数据报会到达其最终目的地,也不保证各个数据报的先后顺序,也不保证每个数据报只到达一次
- UDP 数据报是有长度的。每个 UDP 数据报都有长度,如果一个数据报正确地到达目的地,那么该数据报的长度将随数据一起传递给接收方。而 TCP 是一个字节流协议,没有任何(协议上的)记录边界。
- UDP 是无连接的。UDP 客户和服务器之前不必存在长期的关系。UDP 发送数据报之前也不需要经过握手创建连接的过程。
- UDP 支持多播和广播。
举个栗子
server.js
// 例子:UDP服务端
var PORT = 8989;
var HOST = '127.0.0.1';
var dgram = require('dgram');
var server = dgram.createSocket('udp4');
server.on('listening', function () {
var address = server.address();
console.log('UDP Server listening on ' + address.address + ":" + address.port);
});
server.on('message', function (message, remote) {
console.log(remote.address + ':' + remote.port +' - ' + message);
});
server.bind(PORT, HOST);
然后,创建UDP socket,向端口 8989 发送请求。
client.js
// 例子:UDP客户端
var PORT = 33333;
var HOST = '127.0.0.1';
var dgram = require('dgram');
var message = Buffer.from('My KungFu is Good!');
var client = dgram.createSocket('udp4');
client.send(message, PORT, HOST, function(err, bytes) {
if (err) throw err;
console.log('UDP message sent to ' + HOST +':'+ PORT);
client.close();
});
广播
通过dgram实现广播功能很简单,服务端代码如下。
var dgram = require('dgram');
var server = dgram.createSocket('udp4');
var port = 33333;
server.on('message', function(message, rinfo){
console.log('server got message from: ' + rinfo.address + ':' + rinfo.port);
});
server.bind(port);
接着创建客户端,向地址’255.255.255.255:33333’进行广播。
var dgram = require('dgram');
var client = dgram.createSocket('udp4');
var msg = Buffer.from('hello world');
var port = 33333;
var host = '255.255.255.255';
client.bind(function(){
client.setBroadcast(true);
client.send(msg, port, host, function(err){
if(err) throw err;
console.log('msg has been sent');
client.close();
});
});