【Linux网络】UDP协议详解:透过源码看透“面向数据报”与“缓冲区”的本质

前言:

上文我们讲到了应用层协议:HTTP【Linux 网络】理解并应用应用层协议:HTTP(附简单HTTP服务器C++代码)-CSDN博客

本文了我们来讲讲传输层协议:UDP


传输层

传输层是用于端到端的数据传输的!

为了更好的理解传输层,我们先梳理一下网络数据发送的大致流程:

一. 应用层:由用户给出要发送的数据

二. 传输层:加上对应协议的报头、以及源端口号与目的端口号

三. 网络层:加上对应的协议报头、以及源IP地址与目的IP地址

四. 数据链路层:加上对应协议报头、以及源MAC地址与目的MAC地址

五. 物理层:将数据转化为光信息与电信息发送出去

所以我们说传输层是端到端的数据传输,因为传输层标记端口号。

参考下图(TCP),UDP协议是没有发送缓冲区的

数据发送到主机B后,一层层向上交付,到传输层解析报头,得到对应端口。再将数据放在端口对应软件的缓冲区中。


UDP协议

UDP协议格式如下,分为两部分:

报头:前8字节既报头!包含源端口号、目的端口号、UDP长度、UDP检验和

有效载荷:既引用层传来的数据

UDP长度: 指整个报文的长度(报头 + 有效载荷)

UDP校验和: 如果检验和出错就会直接丢弃。

有效载荷长度 = UDP长度 - 报头长度8字节。


UDP特点

UDP的传输类似于寄信

无连接:UDP知道了IP与端口就直接发送数据了,不需要像TCP一个还行先建立连接才行

不可靠:UDP不保证数据的可靠性,如果因为网络波动等等原因导致数据丢失,那就直接丢失了,没有补救措施

面向数据报:UDP送发的数据一定是完整的报文,不像TCP一样可以控制发送数据的大小

面向数据报

交给UDP多少数据,就发送多少数据,UDP不会进程融合或拆分。 不像TCP,当TCP的发送缓冲区有多个报文时,TCP会将这多个报文"融合"一起发送,让对方一次性全部接收。而UDP是你发送多少保存,对方就必须接收多少次。

UDP缓冲区

UDP是没有发送缓冲区的,但是有接收缓冲区!

接收缓冲区用于当对方应用层忙不过来的时候,暂时保存数据。但是当缓冲区满了的时候,发送过来的数据会被直接丢弃!这又体验了UDP不可靠的特点!

理解报文

在计算机联网互通的时候,一定会进行大量的数据交换:既数据的发送、接收。此次计算机中一定存在大量的报文!!!

对于计算机来说,面对如此大量的报文,是否需要进行管理呢?需要!

如何管理?先描述,再组织!!!

描述:OS中存在一个名为:struct sk_buff的结构体,用于描述报文属性。

管理:OS中再用链表对报文进程组织!

cpp 复制代码
struct sk_buff {
	/* These two members must be first. */
	struct sk_buff		*next;
	struct sk_buff		*prev;

	struct sk_buff_head	*list;
	struct sock		*sk;
	struct timeval		stamp;
	struct net_device	*dev;
	struct net_device	*input_dev;
	struct net_device	*real_dev;

	union {
		struct tcphdr	*th;
		struct udphdr	*uh;
		struct icmphdr	*icmph;
		struct igmphdr	*igmph;
		struct iphdr	*ipiph;
		struct ipv6hdr	*ipv6h;
		unsigned char	*raw;
	} h;

	union {
		struct iphdr	*iph;
		struct ipv6hdr	*ipv6h;
		struct arphdr	*arph;
		unsigned char	*raw;
	} nh;

	union {
	  	unsigned char 	*raw;
	} mac;

	struct  dst_entry	*dst;
	struct	sec_path	*sp;

	/*
	 * This is the control buffer. It is free to use for every
	 * layer. Please put your private variables there. If you
	 * want to keep them across layers you have to do a skb_clone()
	 * first. This is owned by whoever has the skb queued ATM.
	 */
	char			cb[40];

	unsigned int		len,
				data_len,
				mac_len,
				csum;
	unsigned char		local_df,
				cloned,
				pkt_type,
				ip_summed;
	__u32			priority;
	unsigned short		protocol,
				security;

	void			(*destructor)(struct sk_buff *skb);
#ifdef CONFIG_NETFILTER
        unsigned long		nfmark;
	__u32			nfcache;
	__u32			nfctinfo;
	struct nf_conntrack	*nfct;
#ifdef CONFIG_NETFILTER_DEBUG
        unsigned int		nf_debug;
#endif
#ifdef CONFIG_BRIDGE_NETFILTER
	struct nf_bridge_info	*nf_bridge;
#endif
#endif /* CONFIG_NETFILTER */
#if defined(CONFIG_HIPPI)
	union {
		__u32		ifield;
	} private;
#endif
#ifdef CONFIG_NET_SCHED
       __u32			tc_index;        /* traffic control index */
#ifdef CONFIG_NET_CLS_ACT
	__u32           tc_verd;               /* traffic control verdict */
	__u32           tc_classid;            /* traffic control classid */
#endif

#endif


	/* These elements must be at the end, see alloc_skb() for details.  */
	unsigned int		truesize;
	atomic_t		users;
	unsigned char		*head,
				*data,
				*tail,
				*end;
};

在struct sk_buff中存在四个指针,指向报文:

cpp 复制代码
unsigned char		*head,
				*data,
				*tail,
				*end;

head与end分别指向报文空间的起始、结束位置

data指向报文的开始位置

tail指向报文的结束位置

当报文向下传递添加报头时,只需要date指针上移,其他指针不动!

其实到这里我们也明白了,在给报文添加报头 or 解析报头时是不需要移动报文本身,只需要向下or向上交付sk_buff对象即可!通过指针访问修改报文!!!

UDP使用注意事项

我们注意到,UDP协议⾸部中有一个16位的最大长度(含UDP⾸部)。

然而64K在当今的互联网环境下,是⼀个非常小的数字。如果我们需要传输的数据超过64K, 就需要在应用层手动的分包, 多次发送, 并在接收端手动拼装。

相关推荐
林九生7 小时前
【Centos7】CentOS 7 yum源失效解决方案:Could not resolve host mirrorlist.centos.org
linux·运维·centos
福尔摩斯张7 小时前
【实战】C/C++ 实现 PC 热点(手动开启)+ 手机 UDP 自动发现 + TCP 通信全流程(超详细)
linux·c语言·c++·tcp/ip·算法·智能手机·udp
了一梨7 小时前
网络编程:UDP Socket
linux·网络协议·udp
xinxinhenmeihao7 小时前
长效住宅静态IP有什么好处?是选择动态IP还是静态IP好?
服务器·网络·tcp/ip
ChristXlx7 小时前
Linux安装MongoDB(虚拟机适用)
linux·mongodb·postgresql
北方的流星7 小时前
锐捷网络设备(盒式交换机,路由器,EG网关,无线AC、AP)恢复出厂设置
运维·网络·锐捷
AttaGain7 小时前
禁用Ubuntu24.04休眠模式
linux
kaka_19947 小时前
如何解决驱动程序无法通过使用安全套接字层(SSL)加密与 SQL Server 建立安全连接。
linux·安全·ssl
我是谁??7 小时前
windows11的ubuntu子系统如何识别到U盘
linux·运维·ubuntu