• UDP详细理解(实现部分基于linux5.12.12版本内核)


    包的格式

    源端口

    发送方进程所使用的端口号(1-65535)
    RFC768中规定:是否指定源端口可选,未指定是为0
    linux中规定:如果未指定端口号,自动赋予一个非0的端口号

    目的端口

    目标系统中负责接收UDP包的那个应用端口

    长度

    包括包头和有效负荷
    最小的udp包头8字节
    最大UDP有效负荷为65535-8=65527字节
    linux源码中udp发送函数udp_sendmsg中声明完变量后,首先就是判断长度是否符合规范

    if (len > 0xFFFF)
    	return -EMSGSIZE;
    

    校验和

    包括包头、有效负荷、伪负荷。
    对ip源地址目标地址、UDP协议标识符、UDP包长度取1的补码和,然后对结果取11位1的补码和,得到校验和。
    如果字节非偶,后面会补零。仅计算,不传输这个零
    如果校验和为零,会传输比特位均为1的值,这等价于1的补码算术。
    如果传输的校验和位零,表示发送方没有计算校验和。

    传递有效负荷

    1.有效负荷被当作msghdr结构传递给套接字接口处的sendmsg()系统调用。
    2.套接字会检查msghdr结构,在复制它到内核中(除了那些最初驻留在用户地址空间中的实际有效负荷外)。
    综上,UDP发包期间,msghdr结构会原封不动的传递给udp_sendmsg()

    //include/linux/socket.h
    struct msghdr {
    	void		*msg_name;	/* ptr to socket address structure */
    	int		msg_namelen;	/* size of socket address structure */
    	struct iov_iter	msg_iter;	/* data */
    
    	/*
    	 * Ancillary data. msg_control_user is the user buffer used for the
    	 * recv* side when msg_control_is_user is set, msg_control is the kernel
    	 * buffer used for all other cases.
    	 */
    	union {
    		void		*msg_control;
    		void __user	*msg_control_user;
    	};
    	bool		msg_control_is_user : 1;
    	__kernel_size_t	msg_controllen;	/* ancillary data buffer length */
    	unsigned int	msg_flags;	/* flags on received message */
    	struct kiocb	*msg_iocb;	/* ptr to iocb for async requests */
    };
    

    msg_name:不是消息名,他是指向sockaddr_in结构的指针。(sockaddr_in包含IP地址和端口)
    msg_namelen:指出了sockaddr_in结构的长度。
    msg_iter:有效负荷。
    msg_control:msg_control是用于所有其他情况的内核缓冲区;
    msg_control_user:在设置msg_control_is_user时用于recv*端的用户缓冲区。
    msg_control_is_user:(这里为1,暂时未debug,后面补上)
    msg_controllen:辅助数据缓冲区长度。
    以上四个字段规定的缓冲区可以用于传递特定协议的控制消息,具体的控制消息参见recv()。
    msg_flags:接收到的消息上的标志。

    内核会考虑如下标志位:
    MSG_DONTROUTE:目标地址再局域网内,表示规定了不能通过路由。
    MSG_DONTWAIT:防止系统调用阻塞。
    MSG_ERRQUEUE:套接字无法得到包,只会收到一条详细的出错消息。
    内核返回给用户进程的标志位:
    MSG_TRUNC:表示用于接收的缓冲空间不足,因此会丢失一些包数据。
    这四个不是所有的标志位,更详细的参考系统调用手册
    

    msg_iocb:PTR到iocb的异步请求。(这里暂不拓展讲解,本文以了解udp协议特性为主)

    UDP数据报

    udphdr

    struct udphdr {
    	__be16	source;
    	__be16	dest;
    	__be16	len;
    	__sum16	check;
    };
    

    四个unsigned short类型一共8字节
    可以在net/ipv4/udp.c中看到相关校验和的操作
    校验和相关的安全措施较多,最为典型的校验和计算入口为

    static inline u16 udp_csum(u32 saddr, u32 daddr, u32 len,u8 proto, u16 *udp_pkt);
    

    UDP至网络体系结构的集成

    UDP有两个接口:
    1.上行到应用层的接口,PF_INET协议族的套接字所构造。
    2.下行到网络层的接口,

    到应用层的接口

    net/ipv4/udp.c中定义了一个proto

    struct proto udp_prot = {
    	.name			= "UDP",
    	.owner			= THIS_MODULE,
    	.close			= udp_lib_close,
    	.pre_connect		= udp_pre_connect,
    	.connect		= ip4_datagram_connect,
    	.disconnect		= udp_disconnect,
    	.ioctl			= udp_ioctl,
    	.init			= udp_init_sock,
    	.destroy		= udp_destroy_sock,
    	.setsockopt		= udp_setsockopt,
    	.getsockopt		= udp_getsockopt,
    	.sendmsg		= udp_sendmsg,
    	.recvmsg		= udp_recvmsg,
    	.sendpage		= udp_sendpage,
    	.release_cb		= ip4_datagram_release_cb,
    	.hash			= udp_lib_hash,
    	.unhash			= udp_lib_unhash,
    	.rehash			= udp_v4_rehash,
    	.get_port		= udp_v4_get_port,
    	.memory_allocated	= &udp_memory_allocated,
    	.sysctl_mem		= sysctl_udp_mem,
    	.sysctl_wmem_offset	= offsetof(struct net, ipv4.sysctl_udp_wmem_min),
    	.sysctl_rmem_offset	= offsetof(struct net, ipv4.sysctl_udp_rmem_min),
    	.obj_size		= sizeof(struct udp_sock),
    	.h.udp_table		= &udp_table,
    	.diag_destroy		= udp_abort,
    };
    EXPORT_SYMBOL(udp_prot);
    

    到ip层的接口

    net/ipv4/af_inet.中定义了一个含有用于UDP的 net_protocol结构

    static struct net_protocol udp_protocol = {
    	.early_demux =	udp_v4_early_demux,
    	.early_demux_handler =	udp_v4_early_demux,
    	.handler =	udp_rcv,
    	.err_handler =	udp_err,
    	.no_policy =	1,
    	.netns_ok =	1,
    };
    

    UDP数据报收发

    UDP发送包:从套接字接口处的系统调用将包添加到网络接口的输出队列中。
    UDP接收包:将UDP包放入套接字的接收队列中,用户进程通过系统调用从队列中收取包。

    UDP数据报的发送

    int udp_sendmsg(struct sock *sk, struct msghdr *msg, size_t len);
    sk:带有PF_INET发送方套接字状态的sock接口
    msg:传递有效负荷
    len:发送包的长度
    

    UDP数据报的接受

    udp_rcv()
    
  • 相关阅读:
    软件架构感悟.
    浏览器缓存技术
    as到底干嘛了???
    关于WebForm开发问题(给新手的建议)
    疑难问题ASP.NET
    破解hash算法.高手请进,求解.
    (MVC和JVPL模式)Moon.Web架构谈
    Moon.NET框架架构及介绍
    调用API设置安卓手机的Access Point
    gtShell 为你常用的目录建立标签并快速跳转
  • 原文地址:https://www.cnblogs.com/still-smile/p/14925569.html
Copyright © 2020-2023  润新知