本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
在前面的博文中,我画出了TCP/IP数据包发送的流程图。现在开始学习TCP部分。今天由sock_aio_write开始。这是第一个进入TCP发送函数write会调用的第一个socket层的函数。- static ssize_t sock_aio_write(struct kiocb *iocb, const struct iovec *iov,
- unsigned long nr_segs, loff_t pos)
- {
- struct sock_iocb siocb, *x;
- if (pos != 0)
- return -ESPIPE;
/* 申请sock iocb */
- x = alloc_sock_iocb(iocb, &siocb);
- if (!x)
- return -ENOMEM;
- return do_sock_write(&x->async_msg, iocb, iocb->ki_filp, iov, nr_segs);
- }
从函数名字上看,这个函数是一个异步写函数。参数struct kiocb iocb不进行特殊说明了,因为它与TCP/IP协议栈没有直接联系,它存在与所有的I/O操作中。这个函数其实与TCP/IP并不太大联系,更多的是由于VFS。
- int tcp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
- size_t size)
- {
- struct iovec *iov;
- struct tcp_sock *tp = tcp_sk(sk);
- struct sk_buff *skb;
- int iovlen, flags;
- int mss_now, size_goal;
- int sg, err, copied;
- long timeo;
...... ......
- }
与UDP类似,对应于udp_sock,TCP也有struct tcp_sock。因为TCP的要比UDP复杂的多,所以这个tcp_sock也比udp_sock复杂庞大的多。这个struture非常复杂,超过160多行。不过几乎每一个成员变量都有注释,而我目前暂时也没有能力添加更多的注释,所以这里就不粘贴代码了。
不过我要对其中的struct inet_sock进行一点说明。在struct udp_sock中,struct inet_sock inet为其第一个成员变量。而对应struct tcp_sock,其第一个成员变量是struct inet_connection_sock inet_conn,不过struct inet_connection_sock inet_conn的第一个成员变量依然是struct inet_sock inet。所以无论是udp_sock还是tcp_sock,其内存布局上都保证了struct inet_sock inet为第一个成员变量。
- struct inet_sock {
- /* sk and pinet6 has to be the first two members of inet_sock */
- struct sock sk;
- #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
- struct ipv6_pinfo *pinet6;
- #endif
- /* Socket demultiplex comparisons on incoming packets. */
- /*
- 通过与下列的值比较,可以demultiplex收到的包。
- 通过系统调用connect,bind或setsocktopt可以设置下面的部分值。
- */
- __be32 inet_daddr;
- __be32 inet_rcv_saddr;
- __be16 inet_dport;
- /* inet_num 为主机序的port,即inet_sport为其网络序格式 */
- __u16 inet_num;
- __be32 inet_saddr;
- /* 用户指定的ttl值,如为-1,则使用系统默认值 */
- __s16 uc_ttl;
- __u16 cmsg_flags;
- __be16 inet_sport;
- __u16 inet_id;
/* ip option 信息*/
- struct ip_options *opt;
- __u8 tos;
- /*
- 最小的ttl,可以通过/proc指定。
- 若收到的包的ttl小于该值,则drop掉该包
- */
- __u8 min_ttl;
- /* 多播ttl */
- __u8 mc_ttl;
- /*
- PMTU value:
- #define IP_PMTUDISC_DONT 0 /* Never send DF frames */
- #define IP_PMTUDISC_WANT 1 /* Use per route hints */
- #define IP_PMTUDISC_DO 2 /* Always DF */
- #define IP_PMTUDISC_PROBE 3 /* Ignore dst pmtu */
- */
- __u8 pmtudisc;
- /* 下面这些基本上都是socket的option */
- __u8 recverr:1,
- is_icsk:1, /* 是否是connection socket*/
- freebind:1, /* 是否enable IP_FREEBIND option*/
- hdrincl:1, /* 是否enable IP_HDRINCL option*/
- mc_loop:1,
- transparent:1,
- mc_all:1,
- nodefrag:1;
- /* 多播网卡的索引 */
- int mc_index;
- /* 用于发送的多播地址 */
- __be32 mc_addr;
- /* 所有加入的多播组 */
- struct ip_mc_socklist *mc_list;
- /* cork 信息
- 主要用于分片时。具体应用请看前面的博文http://blog.chinaunix.net/space.php?uid=23629988&do=blog&id=186822
- */
- struct {
- unsigned int flags;
- unsigned int fragsize;
- struct ip_options *opt;
- struct dst_entry *dst;
- int length; /* Total length of all frames */
- __be32 addr;
- struct flowi fl;
- } cork;
- };
从上面可以看出,struct inet_sock为TCP/IP协议栈极为重要的结构,它要位于所有的不同sock类型的顶部。主要用于保存不同socket类型公有的特性和信息。组织结构有些类似于C++的基类——尤其是内存布局上。
阅读(423) | 评论(0) | 转发(0) |