首页 > 代码库 > UDP:用户数据报

UDP:用户数据报

    UDP是一个简单的面向数据报的运输层协议:进程的每个输出操作通常会产生一个UDP数据报,并组装成一份待发送的IP数据报。这与面向流的协议不同,如TCP,应用程序产生的数据与真正发送的单个IP数据报并不存在直接的关联。

相关的协议参考tcp/ip协议学习笔记(7)UDP用户数据报协议

UDP输入和输出以及轻量级UDP涉及以下文件:

include/net/udplite.h 定义轻量级UDP专用的函数等

include/linux/udp.h 定义UDP传输控制块等

net/ipv4/udp.c UDP协议的实现

net/ipv4/udplite.c 轻量级UDP的实现

net/core/sock.c 实现传输层通用的函数

net/ipv4/datagram.c 实现UDP的connect调用

net/ipv4/af_inet.c 网络层和传输层接口

UDP的输入与输出


UDP函数之间调用关系比TCP简单的多,和TCP一样,sock结构中的sk_receive_queue成员是UDP的接收队列,通常情况下,接收到UDP数据报会缓存到此,等待用户进程的读取。UDP接收到数据报后的处理要比TCP简单的多,通过校验的UDP数据报,根据类型做不同的处理后被添加到接收队列。

UDP传输控制块

struct udp_sock {
	/* inet_sock has to be the first member */
	struct inet_sock inet;
	int		 pending;	/* Any pending frames ? */
	unsigned int	 corkflag;	/* Cork is required */
  	__u16		 encap_type;	/* Is this an Encapsulation socket? */
	/*
	 * Following member retains the information to create a UDP header
	 * when the socket is uncorked.
	 */
	__u16		 len;		/* total length of pending frames */
	/*
	 * Fields specific to UDP-Lite.
	 */
	__u16		 pcslen;
	__u16		 pcrlen;
/* indicator bits used by pcflag: */
#define UDPLITE_BIT      0x1  		/* set by udplite proto init function */
#define UDPLITE_SEND_CC  0x2  		/* set via udplite setsockopt         */
#define UDPLITE_RECV_CC  0x4		/* set via udplite setsocktopt        */
	__u8		 pcflag;        /* marks socket as UDP-Lite if > 0    */
	__u8		 unused[3];
	/*
	 * For encapsulation sockets.
	 */
	int (*encap_rcv)(struct sock *sk, struct sk_buff *skb);
};
struct inet_sock inet

udp_sock由inet_sock结构扩展而来

int pending

发送状态,其值只能是0或AF_INET,0表示数据已经从UDP套接口发送到IP层,可以继续调用sendmsg()发送数据,AF_INET表示UDP正在处理调用sendmsg()的发送数据,不需要处理目的地址、路由等信息,直接处理UDP数据

unsigned int corkflag

 0     有数据需要发送时,立即发送出去

非0    将UDP数据组成一个单一64KB的UDP数据报后将其发送出去,因此会有延迟
__u16 len

从UDP套接口发送数据到IP层时,标识待发送数据的长度

__u16pcslen
__u16   pcrlen

轻量级UDP,通过UDPLITE_SEND_CSCOV和UDPLITE_RECV_CSCOV选项设置,用于实现控制发送和接收校验和的执行

 0     表示对发送/接收的整个UDP-Lite数据包进行校验

>>=8   表示对发送/接收的UDP-Lite包的前pcslen/pcrlen个字节进行校验

其他值是非法的

UDP的状态

UDP的传输是没有状态的,但事实上,UDP和RAW也借用了TCP的一些值:在一个套接口创建之初,其状态是TCP_CLOSE,当UDP套接口调用connect()后,状态改变为TCP_ESTABLISHED,最后,关闭套接口时又置回TCP_CLOSE,RAW也一样。

轻量级UDP

2.6.20版本的Linux支持UDP-Lite。UDP-Lite协议相对较新,与UDP协议类似,但更适应网络差错率较大而应用对轻微差错不敏感的情况,例如实时视频播放等。那么UDP-Lite与传统的UDP有什么不同呢?传统的UDP协议对其负载(Payload)作完整的校验,如果其中的哪怕只有一位发生了变化,那么整个数据包就有可能被丢弃,在某些情况下,丢掉一个这样的包代价是非常大的,尤其当数据包比较大的时候。在UDP-Lite协议中,一个数据包到底需不需对其负载进行校验,或者是校验多少位都是由用户控制的,

Linux对UDP-Lite协议的支持也是通过在原来的UDP协议的基础上添加了一个setsockopt选项来实现控制发送/接收 Checksum Coverage的

int val = 20;

setsockopt(s, SOL_UDPLITE, UDPLITE_SEND_CSCOV, &val, sizeof(int));

int min = 20;

setsockopt(s, SOL_UDPLITE, UDPLITE_RECV_CSCOV, &min, sizeof(int));

创建一个轻量级UDP套接口很简单

s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE);

UDP:用户数据报