当前位置:   article > 正文

udp协议基本数据包结构_udp数据包结构

udp数据包结构

udp是不可靠、无连接的协议,不可靠是指不能检查到数据包是否安全到达对端,但应用程序可以做保证数据包到达的机制,udp是无连接的协议说明udp的开销小、数据包传输效率高,如果传输的数据小,创建连接的开销、保证数据包可靠发送需要做的工作比数据本身还有多,那么udp是一种好的选择。udp协议头包含有四部分:

(1)、源端口:16位表示取值范围是1-65535。

(2)、目的端口:也是16位。

(3)、长度:长度是16位表示,指udp数据包的整体长度,udp数据包最小是8个字节,所以它能发送的最大负载长度是65535-8。

(4)、校验和:udp的校验和用16位表示,是检验协议头和负载数据。

 

1、UDP协议头数据结构

udp协议头结构体是struct udphdr,结构体元素包括:源端口、目的端口、udp报文整体长度、数据包校验和。结构体定义在include/linux/udp.h文件中。

  1. struct udphdr {
  2. __be16 source; //源端口
  3. __be16 dest; //目的端口
  4. __be16 len; //数据包长度
  5. __sum16 check; //校验和
  6. };

2、UDP控制缓冲区

在Socket BUffer的sk_buff结构体中有一个控制缓冲区,提供给tcp/udp协议头栈中各层协议存放私有数据,udp存放私有数据的结构体是struct udp_skb_cb,定义在include/net/udp.h中

  1. struct udp_skb_cb {
  2. union {
  3. struct inet_skb_parm h4; //ipv4
  4. #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
  5. struct inet6_skb_parm h6; //ipv6
  6. #endif
  7. } header;
  8. __u16 cscov; //udp校验和
  9. __u8 partial_cov; //udp部分校验和
  10. };
  11. //访问缓冲区
  12. #define UDP_SKB_CB(__skb) ((struct udp_skb_cb *)((__skb)->cb))

h4、h6:分别是ipv4、ipv6的选项信息。

cscov:整个udp数据包的校验和。

partial_cov:部分数据的校验和。

udp缓冲区只能通过UDP_SKB_CB宏来访问。

3、udp套接字结构体

udp套接字结构体是struct udp_sock是描述了udp协议的专业特性,struct udp_sock包含了struct inet_sock,struct inet_sock是所有AF_INET地址族域套接字专用数据结构。struct udp_sock在struct inet_sock的基础是扩展了udp数据包需要的全部管理、控制信息。

  1. struct udp_sock {
  2. /* inet_sock has to be the first member */
  3. struct inet_sock inet;
  4. #define udp_port_hash inet.sk.__sk_common.skc_u16hashes[0] //struct inet_sock的数据域
  5. #define udp_portaddr_hash inet.sk.__sk_common.skc_u16hashes[1]
  6. #define udp_portaddr_node inet.sk.__sk_common.skc_portaddr_node
  7. int pending; /* Any pending frames ? 当前是否有等待的数据包 */
  8. unsigned int corkflag; /* Cork is required 是否要阻塞套接字*/
  9. __u16 encap_type; /* Is this an Encapsulation socket? 是否是封装套接字*/
  10. /*
  11. * Following member retains the information to create a UDP header
  12. * when the socket is uncorked.
  13. */
  14. __u16 len; /* total length of pending frames 等待发送数据包的长度*/
  15. /*
  16. * Fields specific to UDP-Lite.
  17. */
  18. __u16 pcslen; //轻套接字等待发送的数据包长度
  19. __u16 pcrlen; //轻套接字等待接受的数据包长度
  20. /* indicator bits used by pcflag: */
  21. #define UDPLITE_BIT 0x1 /* set by udplite proto init function */
  22. #define UDPLITE_SEND_CC 0x2 /* set via udplite setsockopt */
  23. #define UDPLITE_RECV_CC 0x4 /* set via udplite setsocktopt */
  24. __u8 pcflag; /* marks socket as UDP-Lite if > 0 轻套接字标志 */
  25. __u8 unused[3];
  26. /*
  27. * For encapsulation sockets.
  28. */
  29. int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); //封装套接字的接受函数
  30. };

4、udp协议和套接字层的接口

udp协议和套接字层有接口结构是struct proto,定义在net/ipv4/udp.c中,主要是管理套接字和接受发送数据包的处理函数,udp接受数据包时要确定是把数据包分配给那个套接字,以便把数据包放入套接字的接受队列中提供用户读取。udp上所有打开的套接字由udp_v4_hash函数注册到struct sock *udp_hash[UDP_TABLE_SIZE]哈希链表中,端口号就是查询哈希表的哈希值。udp和套接字层的接口struct proto udp_prot定义在net/ipv4/udp.c文件中。

  1. struct proto udp_prot = {
  2. .name = "UDP",
  3. .owner = THIS_MODULE,
  4. .close = udp_lib_close, //关闭套接字
  5. .connect = ip4_datagram_connect, //初始化一个连接
  6. .disconnect = udp_disconnect, //断开套接字
  7. .ioctl = udp_ioctl,
  8. .destroy = udp_destroy_sock,
  9. .setsockopt = udp_setsockopt,
  10. .getsockopt = udp_getsockopt,
  11. .sendmsg = udp_sendmsg, //发送数据包到网络层接口
  12. .recvmsg = udp_recvmsg, //接受应用层数据
  13. .sendpage = udp_sendpage,
  14. .backlog_rcv = __udp_queue_rcv_skb,
  15. .hash = udp_lib_hash,
  16. .unhash = udp_lib_unhash,
  17. .rehash = udp_v4_rehash,
  18. .get_port = udp_v4_get_port,
  19. .memory_allocated = &udp_memory_allocated,
  20. .sysctl_mem = sysctl_udp_mem,
  21. .sysctl_wmem = &sysctl_udp_wmem_min,
  22. .sysctl_rmem = &sysctl_udp_rmem_min,
  23. .obj_size = sizeof(struct udp_sock),
  24. .slab_flags = SLAB_DESTROY_BY_RCU,
  25. .h.udp_table = &udp_table,
  26. #ifdef CONFIG_COMPAT
  27. .compat_setsockopt = compat_udp_setsockopt,
  28. .compat_getsockopt = compat_udp_getsockopt,
  29. #endif
  30. };

upd和套接字层的接口实现了对数据的收发、管理,在AF_INET协议族初始化的过程中完成注册,注册函数是int proto_register(struct proto *prot, int alloc_slab),初始化函数是inet_init在net/ipv4/af_inet.c文件中。

  1. static int __init inet_init(void)
  2. {
  3. struct sk_buff *dummy_skb;
  4. struct inet_protosw *q;
  5. struct list_head *r;
  6. int rc = -EINVAL;
  7. ...
  8. //注册tcp协议实例
  9. rc = proto_register(&tcp_prot, 1);
  10. if (rc)
  11. goto out_free_reserved_ports;
  12. //注册udp协议
  13. rc = proto_register(&udp_prot, 1);
  14. if (rc)
  15. goto out_unregister_tcp_proto;
  16. ...
  17. }

5、udp协议和IP层之间的接口

udp协议和IP层之间的接口由struct net_protoco结构体描述,也是定义了一系列函数指针,主要的函数是接受IP层的数据包udp_rcv和处理ICMP错误信息函数udp_err。

  1. static const struct net_protocol udp_protocol = {
  2. .handler = udp_rcv, //接受IP层数据包函数
  3. .err_handler = udp_err, //icmp错误处理函数
  4. .gso_send_check = udp4_ufo_send_check,
  5. .gso_segment = udp4_ufo_fragment,
  6. .no_policy = 1,
  7. .netns_ok = 1,
  8. };

也是在inet_init()函数中调用inet_add_protocol注册的。

  1. static int __init inet_init(void)
  2. {
  3. ...
  4. //注册传输层的处理函数到inet_protos全局数组中
  5. if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)
  6. printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");
  7. //注册udp处理函数
  8. if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)
  9. printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");
  10. ...
  11. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/84394
推荐阅读
相关标签
  

闽ICP备14008679号