网络协议栈9:connect()函数之前之skb_buff结构体

在使用socket函数创建套接字时,系统创建socket/sock两个结构体,用于本地数据的管理,组织,而这两个数据结构是不会被传送到网络上的,而真正被用来携带数据的结构体是skb_buff,系统在开辟skb_buff结构体空间时,同时把用户数据所需要的空间一起开辟了,也就是一次malloc(sizeof(struct skb_buff)+size)这么多空间,即skb_buff本身的大小,加上用户空间所需要的size大小的空间,由于malloc分配,所以这些空间时连续的一片空间的,也就是说skb_buff结构体数据结束后,接着就是用户的数据,因此,skb_buff结构体的最后成员unsigned char   data[0],定义了一个数组,却没有成员,就是只有数组名,这个数组名所指向的空间恰恰是skb_buff结构体的尾部,也正是用户数据的首部。

 

 

 struct sk_buff {

  struct sk_buff            * volatile next;

  struct sk_buff            * volatile prev;/*这两个字段用于构成 sk_buff结构的队列*/

#if CONFIG_SKB_CHECK

  int                            magic_debug_cookie;/*调试之目的*/

#endif

/*这个指针也是用于构成 sk_buff结构的队列。这个队列就是数据包重发队列,用于 TCP协议中。重发队列是由 sock 结构的 send_head, send_tail 字段指向的队列。send_head 指向这个队列的首部,send_tail 指向这个队列的尾部。而队列的连接是使用 sk_buff结构的 link3 字段完成的。send_head, send_tail是指向 sk_buff 结构的指针,而非 sk_buff_head 结构*/

  struct sk_buff            * volatile link3;/*该数据包所属的套接字*/

  struct sock                 *sk;/*该数据包的发送时间。该字段用于计算往返时间 RTT*/

  volatile unsigned long       when;      /* used to compute rtt's  */

/*该字段也是记录时间,但目前暂未使用该字段用于任何目的*/

  struct timeval            stamp;

/*对于一个接收的数据包而言,该字段表示接收该数据包的接口设备。对于一个待发送的数据

包而言,该字段如果不为 NULL,则表示将要发送该数据包的接口设备*/

  struct device                     *dev;

/*该 sk_buff结构在内存中的基地址,该字段用于释放该 sk_buff 结构*/

  struct sk_buff            *mem_addr;

/*该字段一个联合类型,表示了数据包在不同处理层次上所到达的处理位置。如在链路层上,

eth 指针有效,指向以太网首部第一个字节位置,在网络层上,iph 指针有效指向 IP 首部第

一个字节位置。raw 指针随层次变化而变化,在链路层上时,其等于 eth,在网络层上时,

其等于 iph。seq 是针对使用 TCP 协议的待发送数据包而言,此时该字段值表示该数据包的

ACK值。ACK值等于数据包中第一个数据的序列号加上数据的长度值。*/

  union {

       struct tcphdr   *th;

       struct ethhdr   *eth;

       struct iphdr     *iph;

       struct udphdr  *uh;

       unsigned char  *raw;

       unsigned long seq;

  } h;

/*指向 IP首部的指针,此处特别的分出一个字段用于指向 IP首部主要用于 RAW 套接字*/

  struct iphdr        *ip_hdr;         /* For IPPROTO_RAW */

/*该字段表示 sk_buff结构大小加上数据帧的总长度*/

  unsigned long                   mem_len;

/*该字段只表示数据帧长度。即 len=mem_len – sizeof(sk_buff).*/

  unsigned long           len;

/*这两个字段用于分片数据包。fraglen 表示分片数据包个数,而 fraglist 指向分片数据包队列*/

  unsigned long                   fraglen;

  struct sk_buff            *fraglist; /* Fragment list */

  unsigned long                   truesize;/*同 mem_len*/

  unsigned long           saddr;/*数据包发送的源端 IP地址*/

  unsigned long           daddr;/*数据包最终目的端 IP地址*/

  unsigned long                   raddr;             /* next hop addr 数据包下一站 IP地址*/

/*

acked=1 表示该数据包已得到确认,可以从重发队列中删除。

used=1  表示该数据包的数据已被应用程序读完,可以进行释放。

free=1 用于数据包发送,当某个待发送数据包 free 标志位等于 1,则表示无论该数据包是否

发送成功,在进行发送操作后立即释放,无需缓存。

arp 用于待发送数据包,该字段等于 1 表示此待发送数据包已完成 MAC 首部的建立。arp=0

表示 MAC 首部中目的端硬件地址尚不知晓,故需使用 ARP协议询问对方,在 MAC 首部尚

未完全建立之前,该数据包一直处于发送缓冲队列中(device 结构中 buffs 数组元素指向的

某个队列以及 ARP协议的某个队列中) 。

*/

  volatile char             acked,

                            used,

                            free,

                            arp;

/*

tries 字段表示该数据包已进行 tries 试发送,如果试发送超出域值,则会放弃该数据包的发

送。如对于 TCP建立连接之 SYN 数据包,发送次数超过 3次即放弃发送。

lock 表示该数据包是否正在被系统其它部分使用。

localroute 表示进行路由时是使用局域网路由(localroute=1)还是广域网路由

pkt_type

该数据包的类型,可取如下值:

PACKET_HOST

这是一个发往本机的数据包。

PACKET_BROADCAST

广播数据包。

PACKET_MULTICAST 

多播数据包。

PACKET_OTHERHOST

该数据包是发往其它机器的,如果本机没有被配置为转发功能,该数据包即被丢弃

*/

  unsigned char                   tries,lock,localroute,pkt_type;

#define PACKET_HOST              0            /* To us */

#define PACKET_BROADCAST  1

#define PACKET_MULTICAST   2

#define PACKET_OTHERHOST  3            /* Unmatched promiscuous */

/*users  使用该数据包的模块数*/

  unsigned short           users;             /* User count - see datagram.c (and soon seqpacket.c/stream.c) */

/*同 pkt_type*/

  unsigned short           pkt_class;       /* For drivers that need to cache the packet type with the skbuff (new PPP) */

#ifdef CONFIG_SLAVE_BALANCING

  unsigned short           in_dev_queue;/*该字段表示该数据包是否正在缓存于设备缓存队列中*/

#endif 

  unsigned long                   padding[0];/*填充字节。目前定义为 0 字节,即无填充*/

  unsigned char                   data[0];/*指向数据部分。数据一般紧接着该 sk_buff结构,也有可能在任何地址处*/

};

 

同时还有一个结构体

struct sk_buff_head {

  struct sk_buff            * volatile next;

  struct sk_buff            * volatile prev;

#if CONFIG_SKB_CHECK

  int                            magic_debug_cookie;

#endif

};

 

它的成员与 sk_buff 结构的开始几个字段时一样的,如此处理可以利用指针转化将 sk_buff_head 当作 sk_buff 结构使用,反过来也如此。

系统就是通过上述两个结构体来组织数据,并形成队列,最终在网络上传输

posted on 2012-01-09 10:35  image eye  阅读(1883)  评论(0编辑  收藏  举报