在使用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 结构使用,反过来也如此。
系统就是通过上述两个结构体来组织数据,并形成队列,最终在网络上传输