




已阅读5页,还剩39页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
本科毕业论文 题 目linux下tcp协议栈源代码分析和研究姓 名学 号专 业计算机科学与技术指导教师职 称讲 师中国武汉分类号 密级华中农业大学本科毕业论文 linux下tcp协议栈源代码分析和研究tcp protocol stack source code analysis and research under linux operating学生姓名:学生学号:学生专业:计算机科学与技术指导教师:华中农业大学理学院华中农业大学本科毕业论文(或设计)目 录摘要iiabstractii前言11linux协议栈概要22缓存sk_buff简介32.1sk_buff的定义32.2与sk_buff相关的函数52.3sk_buff_head定义及相关操作63tcp协议相关数据结构的介绍83.1socket结构83.2sock结构93.3tcp_opt结构104tcp连接的建立和关闭124.1tcp连接的建立124.2tcp连接的关闭145tcp数据的发送与接收165.1数据的发送165.2数据的接收196tcp的流量控制与拥塞控制206.1tcp的流量控制206.1.1 初始化接收窗口206.1.2 通告窗口的计算206.1.3 发送窗口的更新216.2tcp的拥塞控制21结论28参考文献28致谢29附录30linux下tcp协议栈源代码分析和研究摘 要linux的网络协议栈是内核的一部分,它的实现是基于tcp/ip协议栈的,共分五层,分别是:应用层、bsd socket层、inet socket层、网络层和数据链接/硬件层。这是继承了unix的网络系统,现在linux的网络系统不断注入了新的理论。 我要研究的是linux下网络协议栈一个通信协议tcp协议栈。tcp协议是面向对象的协议,本论文主要从缓存sk_buff,tcp相关数据结构,tcp连接的建立与关闭,tcp数据的发送与接收,tcp的流量控制与拥塞控制这几方面阐述我对tcp协议栈的理解,主要研究了tcp在内核中如何实现,以及一些算法的实现。关键词linux2.4.x;tcp协议栈;流量控制;拥塞控制tcp protocol stack source code analysis and research under linux operatingabstractlinux network protocol stack is a part of kernel,the realization of it is based on the tcp / ip protocol stack, and is divided into five layer, namely: the application layer, bsd socket layer, inet socket layer, network layerand data link / hardware layer . this is inherited from the unix network system, now the network system of linux constantly inject new theories.i would like to study a communication protocol of the network protocol under linux i expound my understanding of tcp mainly from the cache sk_buff, tcp-related data structure, tcp connection establishment and closure, tcp data send and receive, tcp flow control and tcp congestion control, the main study is the how to achieve tcp in the kernel, as well as the realization of a number of algorithms.key wordslinux2.4.x;tcp protocol stack;flow control;congestion control 40前言linux是当今使用最广泛的操作系统之一,其涉入的领域很多,有嵌入式、信息安全、网络系统等。我研究的问题是linux下tcp协议栈,其意义是非常大的,可以说当今与未来的信息技术不再是确定在某一个地区了,而是通过网络传布全世界,信息技术和网络的使用越来越多,其带来的经济效益、科研效益是不可低估的,因此研究网络系统是非常有必要的,而我现在研究的是网络系统的一个小分支,以小觑大,我对tcp协议栈的研究意义也是不可忽视的。虽然linux给国内外的科研和应用带来了巨大的方便和作用,但现在真正能完全理解linux内核的人却不多,尤其是国内,这几年才真正认识到linux的重要性,并且投入大量的人力和物力来研究linux,国际上也一度掀起了linux热潮,并且这种潮流在一直高涨,伴随出现了许多的科研机构和开发linux的公司,如:redhat公司。现在我国研究linux的水平,不管是应用方面还是理论方面都不及国外,尤其是不及美国,有关linux方面的经典书籍都是翻译过来的,中国自己写的linux书籍在linux爱好者中褒贬不一,可见中国的linux水平有待进一步的提高。当今it行业的发展,已经离不开linux了,接触linux的人在不断上升,微软也感觉到了压力,把windows的一部分源码公开,以争取一定得竞争,但这并不能改变linux的发展趋势,它的公开源代码和安全性带给商家和爱好者极大的吸引力。因此,研究linux是非常有价值和意义的。(田光宇和王东来,2009)学习和研究linux操作系统是我国软件业走上独立自主和实现腾飞的重要途径。由于操作系统是所有软件赖以生存的基础,但我国操作系统市场长期被国外公司垄断,因而民族软件业的发展非常迟缓,在国际上处于不利地位。面对这种局面,出路何在?linux的开放性和技术的先进性可以帮助我们打破国外公司的垄断,我们可以借鉴它的技术加速国产操作系统、嵌入式软件和信息安全产品的开发。所以在1999年7月,国家计委、科技部向社会公布的我国重点发展的高技术项目中,把linux操作系统的研究放到一个重要的位置,这说明我国政府对linux和发展自主版权操作系统的重视。我所研究的是linux网络中的一小部分:tcp协议栈,本论文是基于linux 2.4.x的网络协议栈。有关tcp协议栈的代码只有上千行,我分六章来阐述我的研究和理解。第一章是linux网络协议栈概要,主要简单介绍一下linux的网络模型及框架;第二章是缓存sk_buff简介,因为sk_buff在网络协议的实现中有非常重要的作用,所以我在此对sk_buff的成员变量和对它的操作函数作了介绍;第三章是tcp相关数据结构的介绍,一个好的系统离不开好的数据结构,介绍tcp相关数据结构有利于更好的理解tcp协议栈;第四章是tcp连接的建立和关闭,因为tcp协议是面向连接的,因此在发送和接收数据前必须要建立好连接,在完成后要关闭连接;第五章是tcp数据的发送与接收,在建立好了连接后,接下来就是数据传送,本章讲tcp如何发送和接收数据;第六章tcp的流量控制与拥塞控制,这章是tcp协议栈的重点,也是难点。1 linux协议栈概要在linux的网络系统中,完整的实现了tcp/ip协议,可以把它分为硬件层/数据链路层、ip层、inet socket层、bsd socket层和应用层五部分,其中内核包括前面四部分。bsd socket层主要是一些系统调用,用来完成用户命令以实现对数据的发送或接收;inet socket层实现比ip协议层次高,实现对ip分组排序、控制网络系统效率等功能; ip层是在tcp/ip网络协议栈中心的互联网层实现;硬件层在tcp/ip协议栈中和数据链路层区分不明确,因此可以把硬件驱动和硬件发送工作的层次称为硬件层/数据链路层。(唐续等,2003)如图1说明了linux中基于tcp/ip协议的网络系统体系结构:内核应用层bsd socket层inet socket层ip层硬件层网络设备接口tcpudp图1 linux下的网络结构fig. 1 the network structure of linux下面对从应用层到网络设备接口硬件之间数据的流程走向做简略介绍。应用层中的操作对象是socket文件描述符,通过文件系统定义的通用接口,使用系统调用从用户空间切换到内核空间,控制socket文件描述符对应的就是bsd socket的操作,从而进入bsd socket层的操作。在bsd socket层中,操作的对象是socket结构,每一个这样的结构对应的是一个网络连接,通过网络地址族的不同来区分不同德操作方法,判断是否应该进入到inet socket层,这一层的数据存放在msghdr结构的变量中。在inet socket层中,根据建立连接的类型,分成面向连接和面向无连接两种类型,这就是区分tcp和udp协议的主要原则,在这一层中操作对象是sock结构类型的数据,而数据存放在sk_buff结构中。从inet socket层到ip层,主要是路由过程,发送时根据发送的目的地址确定需要使用的网络设备接口和下一个需要传送到的机器地址,接收数据的时候需要在ip层判断改数据包时要发送给上一层协议还是需要做一个ip转发,将数据传递给下一个主机。从ip层到硬件层,也就是到网络接口设备驱动程序,即是有关硬件相关的控制方法。(李善平和刘文峰,2002)(stevens w r,1995)linux中inet socket及以下层的数据都是用sk_buff存储,因此网络协议的实现很大一部分是对sk_buff的操作。以下对sk_buff做简略的介绍。2 缓存sk_buff简介2.1 sk_buff的定义sk_buff是一个控制结构,通过它才可以访问网络报文里的何种数据,所以在分配网络报文存储空间时,同时也分配它的控制结构sk_buff。在这个控制结构里,有指向网络报文的指针,也有描述网络报文的变量。下面是sk_buff的定义。struct sk_buff struct sk_buff * next; struct sk_buff * prev; struct sk_buff_head * list; /*以上三个变量将sk_buff链接到一个双向循环链表中*/ struct sock *sk; /*此报文所属的sock结构,此值在本机发出的报文中有效,从网络设备收到的文此值为空。*/ struct timeval stamp; /此报文收到时的时间 struct device *dev; /收到此报文的网络设备 union struct tcphdr *th; struct udphdr *uh; struct icmphdr *icmph; struct igmphdr *igmph; struct iphdr *ipiph; struct spxhdr *spxh; unsigned char *raw; h;union struct iphdr *iph; struct ipv6hdr *ipv6h; struct arphdr *arph; struct ipxhdr *ipxh; unsigned char *raw; nh; union struct ethhdr *ethernet; unsigned char *raw; mac; /*以上三个union结构依次是传输层,网络层,链路层的头部结构指针。这些指针在网络报文进入这一层时被赋值,其中raw是一个无结构的字符指针,用于扩展的协议。*/ struct dst_entry *dst; /此报文的路由,路由确定后赋此值 char cb48; /*用于在协议栈之间传递参数,参数内容的涵义由使用它的函数确定。*/ unsigned int len; /*此报文的长度,这是指网络报文在不同协议层中的长度,包括头部和数据。在协议栈的不同层,这个长度是不同的。*/ unsigned char is_clone, cloned; /*这两个变量描述此控制结构是否是clone的控制结构。一个网络报文可以对应多个控制结构,其中只有一个是原始结构,其他的都是clone出来的。由于可能存在多个控制结构,所以在释放网络报文时要确定它所有的控制结构都已被释放。*/ unsigned char pkt_type, /*网络报文的类型,常见的有packet_host,代表发给本机的报文;还有packet_outgoing,代表本机发出的报文。 */ unsigned short protocol; /链路层协议 unsigned int truesize; /*此报文存储区的长度,这个长度是16字节对齐的 */ unsigned char *head; unsigned char *data; unsigned char *tail; unsigned char *end; /*以上四个变量指向此报文存储区。*/ _u32 fwmark; /防火墙在报文中做的标记 ;在sk_buff中指针head和end是指向存储空间的开始地址和结束地址,而data和tail是指向网络报文的开始地址和结束地址。在存储空间前部一般要为协议头部预留空间,而存储空间是16字节对齐,在尾部往往会有一定得剩余空间。(李善平,刘文峰,2002)如图2:页碎片区headroomdata(payload)nr_fragtailroomdatereffrags2frag_listfrags0frags1fragmax_skb_frag页碎片1页碎片2从属sk_buff1从属sk_buff2.headdatatailendskb_shared_info图2 sk_buff与网络报文存储空间的关系fig. 2 the relationship between sk_buff and network packet storage space2.2 与sk_buff相关的函数与sk_buff相关的函数涉及到网络报文存储结构和控制结构的分配、复制、释放,以及控制结构里的各指针的操作,还有各种标志的检查。重要的函数说明如下: (1)struct sk_buff *alloc_skb(unsigned int size,int gfp_mask) 分配大小为size的存储空间存放网络报文,同时分配它的控制结构。size的值是16字节对齐的,gfp_mask是内存分配的优先级。常见的内存分配优先级有gfp_atomic,代表分配过程不能被中断,一般用于中断上下文中分配内存;gfp_kernel,代表分配过程可以被中断,相应的分配请求被放到等待队列中。分配成功之后,因为还没有存放具体的网络报文,所以sk_buff的 data,tail指针都指向存储空间的起始地址,len的大小为0,而且 is_clone和cloned两个标记的值都是0。 (2)struct sk_buff *skb_clone(struct sk_buff *skb, int gfp_mask) 从控制结构skb中 clone出一个新的控制结构,它们都指向同一个网络报文。clone成功之后,将新的控制结构和原来的控制结构的 is_clone,cloned两个标记都置位。同时还增加网络报文的引用计数(这个引用计数存放在存储空间的结束地址的内存中,由函数atomic_t *skb_datarefp(struct sk_buff *skb)访问,引用计数记录了这个存储空间有多少个控制结构)。由于存在多个控制结构指向同一个存储空间的情况,所以在修改存储空间里面的内容时,先要确定这个存储空间的引用计数为1,或者用下面的拷贝函数复制一个新的存储空间,然后才可以修改它里面的内容。 (3)struct sk_buff *skb_copy(struct sk_buff *skb, int gfp_mask) 复制控制结构skb和它所指的存储空间的内容。复制成功之后,新的控制结构和存储空间与原来的控制结构和存储空间相对独立。所以新的控制结构里的is_clone,cloned两个标记都是0,而且新的存储空间的引用计数是1。 void kfree_skb(struct sk_buff *skb) 释放控制结构skb和它所指的存储空间。由于一个存储空间可以有多个控制结构,所以只有在存储空间的引用计数为1的情况下才释放存储空间,一般情况下,只释放控制结构skb。 (4)unsigned char *skb_put(struct sk_buff *skb, unsigned int len) 将tail指针下移,并增加skb的 len值。data和 tail之间的空间就是可以存放网络报文的空间。这个操作增加了可以存储网络报文的空间,但是增加不能使tail的值大于end的值,skb的 len值大于truesize的值。 (5)unsigned char *skb_push(struct sk_buff *skb, unsigned int len) 将data指针上移,并增加skb的 len值。这个操作在存储空间的头部增加了一段可以存储网络报文的空间,上一个操作在存储空间的尾部增加了一段可以存储网络报文的空间。但是增加不能使data的值小于head的值,skb的 len值大于truesize的值。 (6)unsigned char * skb_pull(struct sk_buff *skb, unsigned int len) 将data下移,并减小skb的 len值。这个操作使data指向下一层网络报文的头部。 (7)void skb_reserve(struct sk_buff *skb, unsigned int len) 将data指针和tail指针同时下移。这个操作在存储空间的头部预留 len长度的空隙。 (8)void skb_trim(struct sk_buff *skb, unsigned int len) 将网络报文的长度缩减到 len。这个操作丢弃了网络报文尾部的填充值。 (9)int skb_cloned(struct sk_buff *skb) 判断skb是否是一个 clone的控制结构。如果是clone的,它的cloned标记是1,而且它指向的存储空间的引用计数大于1。(毛德操,胡希明,2001)2.3 sk_buff_head定义及相关操作在网络协议的实现中,有时需要把许多网络报文放在一个队列中做异步处理。linux就定义了sk_buff_head来实现,把sk_buff结构组成一个双向链表。其定义如下:struct sk_buff_head /* these two members must be first. */* 链表指针置于sk_buff_head结构的前两个域,目的是让sk_buff_head结构和sk_buff结构能相互进行强制转换*/struct sk_buff* next;struct sk_buff* prev;_u32qlen;/* 由该结构引导的链表的节点个数 */spinlock_t lock;/*对一个sk_buff结构链表操作时,需要对sk_buff_head中的锁成员作判断,保证数据改动的同步*/;sk_buff在网络协议中是频繁访问的数据结构,通过sk_buff_head结构把sk_buff结构连接成一个双向链表,这样可以提高访问速度。sk_buff_head不一定在链表的开端,但可以通过这个指针将链表中的所有数据引用到。如图3:sk_buffsk_buffsk_buff_headsk_buff数据数据数据图3 sk_buff结构与sk_buff_head结构组成的链表fig. 3 the list composed of sk_buff and sk_buff_head与链表相关的函数,其功能无非是添加、删除链表上的节点。重要的函数说明如下: void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk), 将newsk加到链表 list的头部。 void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk),将newsk加到链表 list的尾部。 struct sk_buff *skb_dequeue(struct sk_buff_head *list) ,从链表 list的头部取下一个 sk_buff。 struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list) ,从链表 list的尾部取下一个 sk_buff。 void skb_insert(struct sk_buff *old, struct sk_buff *newsk) ,将newsk加到old所在的链表上,并且 newsk在old的前面。 void skb_append(struct sk_buff *old, struct sk_buff *newsk) ,将newsk加到old所在的链表上,并且 newsk在old的后面。 void skb_unlink(struct sk_buff *skb) ,将skb从它所在的链表上取下。 以上的链表操作都是先关中断的。这在中断上下文中是不需要的,所以另外有一套与上面函数同名但是有前缀“_”的函数供运行在中断上下文中的函数调用。(周宗照等,2003)3 tcp协议相关数据结构的介绍与tcp协议相关的数据结构是实现tcp协议栈的关键,有socket结构、sock结构、tcp_opt结构、tcp_skb_cb等,这里我们讨论这几个重要的结构,从而为理解tcp协议做好准备,下面一一做出分析。3.1 socket结构struct socketsocket_statestate;unsigned longflags;struct proto_ops*ops;struct inode*inode;struct fasync_struct*fasync_list;/*asynchronous wake up list*/struct file*file;/* file back pointer for gc*/struct sock*sk;wait_queue_head_twait;shorttype;unsigned charpasscred;此结构是工作在bsd socket层的一个控制结构,在应用程序中通过使用一个socket的文件描述符和bsd socket中的一个socket对应。state是表示当前应用程序控制的套接字的状态内容。主要有ss_connected和ss_unconnected两种状态,前者表示已经建立连接,后者表示已经断开连接。flag向这个socket传递一些控制信息,可以在应用层通过系统调用修改flag数据,从而改变bsd socket层对连接的控制情形。ops是proto_ops类型的指针,它指向在bsd socket层上对不同地址族的操作函数集合,从而确定从bsd socket层到下层的函数接口。对bsd socket下一层操作的函数集合,即进入下一层的接口函数。linux中每个文件都被描述称为一个inode。bsd socket也是一样。每一个socket文件描述符和一个bsd socket对应;同时,每一个文件描述符都要和一个inode对应,那么从bsd socket中也可以引用到这个inode。在处理一个bsd socket的时候,都需要和这些不同的文件之间进行异步处理,如果进程选择处理这个文件,那么所有的相关的进程都要通知到。在fasync_list成员中存放了这些信息。file指针用于socket对应的file文件指针。sk指针是指向在bsd socket层下一层协议中用于引用网络传输数据和进行控制的结构指针。这里是inet socket层中的sock结构指针,同时在inet socket里面也有指向bsd socket的指针,他们的关系如图4:sksocket图4 socket结构与sock结构之间的关系fig. 4 the relationship between socket and sockwait是wait_queue_head类型的数据,表示等待在这个socket结构上的任务列表。从socket结构到sock结构传递时,直接将wait传给sock的睡眠成员。type是指数据包的类型,这些类型代表了应该使用哪种协议进行传输。(李善平和刘文峰,2002)3.2 sock结构在inet socket数据结构中,管理数据包存放和调度的数据结构是sock,在inet socket层以下的网络层次上也会使用sock结构。sock结构源代码参见附录。这里只对其里面的大部分成员做出解释,以理解它的作用。成员daddr、dport分别表示目的地址和目的端口。成员rcv_saddr、sport分别表示本地用于接收的源地址和源端口,rcv_saddr要在套接字绑定之后才初始化。bound_dev_if若非零,则表示sock结构对应的网络接口设备索引号。在linux中采用hash表技术处理这些sock链表,next和pprev就是用来实现各种哈希表的。bind_next、bind_pprevlaing成员将重用一个端口sock结构用双向链表链接起来。state表示当前的连接状态,尤其是对tcp协议,它建立一个可靠的连接的过程,实际上就是一个有穷状态机的变换过程,而有穷状态机的状态就保存在state中。family是指sock的地址族,这个数值从bsd socket中延续下来。如果对该sock设置了so_reuseaddr属性,就将reuse置1。shutdown用来标志在传输的过程中是否已经发送结束。refcnt是指该sock的引用计数。lock是该sock结构的同步锁。一些和套接字对内存申请有关的成员。revbuf和sndbuf是系统目前还有多少缓冲区空间用于接收和发送数据。rmem_alloc和wmem_alloc诗系统已经申请用来接收和发送数据的缓冲区大小,omem_alloc是可能用作其他用途的缓冲区大小。allocation是申请内核中内存的时候使用的参数值。sleep是等待在该sock上的进程队列。在接收到带外数据的时候,需要给某进程发送信号表示数据已经收到,这个进程的进程号记录在proc中。在accept()系统调用的时候,会返回一个新的socket结构用于数据传输,原来的socket继续监听外部的连接请求。这两个socket结构对应的sock结构通过成员pair指针引用。prot是指向proto结构的指针。在inet socket层上的操作函数都集中在proto结构中,通过这个数据结构中定义的函数接口,确定在inet socket处理网络数据的方式,包括从上一层获得数据用于发送和从下一层获得处理并准备传递给上一层。不同的ine协议在proto结构的实现不同。对于tcp,就是tcp_prot;对于udp来说就是udp_prot。socket是该inet socket相关的bsd socket指针。在前面介绍socket中的sk是已经用图表示过了。sock结构的最后是六个函数指针,是对inet socket的回调函数。在inet socket作出处理的时候,适当的情况下调用这些函数来完成后续工作。3.3 tcp_opt结构tcp_opt结构主要是对tcp协议的一些描述,如发送序号、确认帧、发送和接收窗口大小、拥塞控制算法等。源代码参见附录。下面是对结构中一些重要成员的理解。成员tcp_header_len是表示tcp数据包的tcp头部的大小,由于tcp头有20个字节的固定,但后面还可以有4n(n必须是整数)字节是根据需要而增加的选项,因此tcp的头部就不能固定大小了,必须用一个变量来保存它的长度。tcv_nxt和snd_nxt分别表示下一个接收序号和下一个发送序号。结构成员ack是用来对推迟应答进行控制的数据结构。snd_wll、snd_wnd、max_windows是对tcp发送窗口的表述。snd_wll用于最后窗口的段序列号,snd_wnd是发送窗口的大小,max_windows是到现在为止发送窗口的最大值。由于tcp发送窗口是由接收端控制的,因此这些变量的值是不断变化的。成员srtt是rtt(报文往返时间)的修正值。发送端每接收到一次新的响应,产生出一个新的rtt样本。为了取出rtt样本的随机抖动,系统利用加权平均算法对样本进行修正,为了避免内核浮点运算,rtt的修正值(srtt)是实际rtt均值的8倍,在迭代过程中,srtt收敛于8倍的rtt。在修正rtt样本值的同时,发送端还跟踪样本的抖动性。成员mdev、mdev_max、rttvar、rtt_seq、rto就是对它的表述。rtt的抖动用中心差(mdev)来衡量,它是rtt于rtt均值偏差绝对值的加权平均,它的值越大说明rtt抖动得越厉害。mdev_max变量用来跟踪mdev的最大值,它再经过修正成rttvar,描述rtt抖动的最大范围。发送端的重发超时被设为rtt均值和rttvar的和。snd_ssthresh是发送的慢启动门限,当拥塞发生的时候snd_ssthresh设置为当前窗口的一半。成员snd_cwnd_cnt是线性增长数。当拥塞窗口达到拥塞时大小的一半2(即门限值)时,tcp进入拥塞避免阶段,降低发送端拥塞窗口的增大速度,用线性值snd_cwnd_cnt递增取代2的幂的增长方式。成员snd_cwnd_clamp是发送的拥塞窗口的钳制值(即拥塞窗口不能超过该值)。成员timeout、retransmit_timer、delack_timer是有关定时的变量。timeout表示时间戳;retransmit_timer是重发定时器,在发送一个数据报的同时,启动一个数据重发定时器;delack_timer是推迟应答的定时器。rcv_wnd和rcv_wup分别表示目前接收窗口的大小和接收窗口的起始位置。接收的tcp选项有tstamp_ok、wscale_ok、sack_ok。其中tstamp_ok是从接收到的syn报文段中,判断是否设置时间戳选项的标志。wscale_ok是从接收到的syn报文段中,判断是否设置窗口扩大选项的标志。ack_ok是从接收到的syn报文段中,最低位是支持选择性应答的标志,若为带有数据的包则是使用tcp版本位图,值为0时采用reno版的tcp;倒数第2位为1时,支持sack;倒数第3位为1时,支持fack。keepalive_time是表示在启动保活定时器到发送探测报文之间的时间长度。keepalive_intvl是表示发送相邻两个探测报文段的间隔时间. 成员linger2,在fin_wait_2状态我们已经发出了fin,并且另一端也已对它进行确认。除非我们在实行半关闭,否则将等待另一端的应用层意识到它已收到一个文件结束符说明,并向我们发一个fin 来关闭另一方向的连接。只有当另一端的进程完成这个关闭,我们这端才会从fin_wait_2状态进入time_wait状态。这意味着我们这端可能永远保持这个状态。另一端也将处于close_wait状态,并一直保持这个状态直到应用层决定进行关闭。为了解决这个问题,设置一个定时器,如果这个连接闲置一个特定的时间长度(linger2)后,tcp将进入close状态。当然tcp_opt结构中的成员不止这些的,上面是其中的主要成员。主要从推迟应答进行的控制、rtt(报文段往返时间)测量、慢启动和拥塞控制、在发送和接收路径上常用的定时器、接收的tcp选项 (一般为最新接收到的包, 也有针对syn报文段的)这几个主要方面作出了解释。(毛德操和胡希明,2001)4 tcp连接的建立和关闭4.1 tcp连接的建立 在应用层,连接的建立时调用来函数connect()。其形式为:int connect(int sockfd,const struct sockaddr *serv_addr,int addlen),其中sockfd为套接字对应的文件描述符,serv_addr为服务器端的协议地址结构,addlen为该地址的长度。tcp连接的建立必须经过三次握手。在bsd socket层有个系统调用sys_connect(),应用程序通过它进入内核态,因为根据linux网络系统的布局,从bsd socket层以下都是在内核态。在这个系统调用sys_connect()中,首先由套接字对应的文件描述符查找到响应的socket结构,然后将服务器端的地址结构从用户空间拷贝到内核地址空间中去,并且通过sock-ops-connect(sock, (struct sockaddr *) address, addrlen,sock-file-f_flags)函数指针;进入下一层inet socket层。在inet socket层调用的是inet_stream_connect(),该函数先锁定sock结构,防止其他进程同时对其操作,然后通过swich语句对不同状态做出不听反应,只有当socket状态为ss_unconnected且sock状态为tcp_close时方可建立连接,如果是此状态则通过sk-prot-connect(sk, uaddr, addr_len),调用tcp_v4_connect()函数,进入下一层,然后把socket状态设置为ss_connecting进入连接状态,等待三次握手的完成,在握手中,如果进程不等待连接完成则系统调用返回,否则调用inet_wait_for_connect()等待连接完成。一系列连接完成后,设置socket状态为ss_connected,三次握手过程完成,连接建立成功,释放锁。在tcp层调用的是tcp_v4_connect(),要求必须是internet地址族协议,并设置了路由。先用连接的目的地址作为下一跳的初值,然后进入ip层选路,根据源地址、目的地址、tos以及出口网络设备选择一条路由。如果是多播或广播通信,则不能采用tcp协议。再调用函数sk_dst_set()将rt-u_dst的内存传给sk,那么在网络传输的时候可以通过sk得到路由的信息,将rt-rt_dst存放在daddr中,表示实际应该传送到得写一个网络地址。最后调用tcp_connect()初始化tcp头,并设置tcp处理需要的定时器,一次connect()建立的过程就结束了。(姜照林,吴军强,2008)(braden r(ed).rfc 2205)下面介绍一下三次握手的函数调用关系:客户端:(发起连接请求)tcp_v4_connect-tcp_connect_init-tcp_transmit_skb-icsk-icsk_af_ops-send_check(tcp_v4_send_check)- icsk-icsk_af_ops-queue_xmit(ip_queue_xmit) - inet_csk_reset_xmit_timer。通过这个过程向外发送syn包,并设置新发送的定时器。如果过一段时间没应答:tcp_retransmit_timer- tcp_retransmit_skb - tcp_transmit_skb其余操作跟上面的相同。服务器端:(接收syn,并返回syn/ack)tcp_v4_rcv- tcp_v4_do_rcv - tcp_v4_hnd_req- tcp_rcv_state_process - icsk-icsk_af_ops-conn_request (tcp_v4_conn_request) - tcp_v4_init_sequence- tcp_v4_send_synack- ip_build_and_send_pkt。客户端:(接收syn/ack,并返回ack)tcp_v4_rcv - tcp_v4_do_rcv - tcp_rcv_state_process - tcp_rcv_synsent_state_process- tcp_ack- tcp_store_ts_recent- tcp_initialize_rcv_mss- tcp_send_ack-tcp_transmit_skb- tcp_urg- tcp_data_snd_check服务器端:(接收ack)tcp_v4_do_rcv - tcp_v4_hnd_req - tcp_check_req -inet_sk(sk)-icsk_af_ops-syn_recv_sock- tcp_rcv_state_process - tcp_sequence。(朱晶,2009)4.2 tcp连接的关闭在应用层,客户端关闭连接的函数形式如下:int close(int sockfd);其中sockfd是套接字对应的文件描述符。关闭函数对应的结构成员是sock_close()函数,而从文件系统中的close系统条用可以条用到这个函数,调用流程如图5:filp_close()fput()f_op_release()sys_close()sock_close()图5 从sys_close()到sock_close()的流程fig. 5 the process from sys_close to sock_closebsd socket层调用sock_close(),检查inode是否为空,不为空则将和该filp对用的所有fasvnc_list队列清空,这些文件都需要用到socket,在socket关闭后,这些文件不能再用,因此需要在这个队列中将和该socket结构对应的数据项清空,然后调用sock_release()。在sock_release()调用和该socket对应协议的关闭函数,tcp协议是调用tcp_close;如果fasync_list成员不空,则出错;然后对每个处理器维持的一张正在使用的socket数目做减一处理;使用socket结构对应inode,将socket指针的file成员设置为null。在inet socket层调用inet_release()函数,该函数先判断sock结构变量sk是否为空,不为空则把它设为空,并通过sk-prot-close(sk, timeout)进入下一层,调用tcp_close()函数。tcp层的函数tcp_close()把tcp状态设置为tcp_close关闭状态,若是服务器端则停止监听,释放sk_buff缓存,然后等待服务器端和客户端各自终止,至此tcp连接关闭。下面具体表述一下tcp连接终止的过程(四次握手):由于tcp连接是全双工的,因此每个方向都必须单独进行关闭。这原则是当一方完成它的数据发送任务后就能发送一个fin来终止这个方向的连接。收到一个 fin只意味着这一方向上没有数据流动,一个tcp连接在收到一个fin后仍能发
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 吊车安全教育培训
- 标准化体系管理
- 2024-2025学年统编版小学道德与法治小升初模拟试卷及参考答案
- 绿色农业的投资潜力
- 历史遗产的探索与保护
- 绿化校园 持续环保
- 旅游业新晋动态
- 旅游业精英之路
- 2025关于广告平面设计委托合同范本
- 2025超市供应合同
- 2025年重庆中考押题道德与法治试卷(一)(含答案)
- 肿瘤的内分泌治疗护理
- 东北三省三校2025届高三下学期第二次联合模拟考试数学试题及答案
- 2025年山东鲁泰控股集团有限公司下属驻陕西煤矿企业招聘(150人)笔试参考题库附带答案详解
- 2025届上海市浦东新区高三二模英语试卷(含答案)
- 2025年全民国家安全教育日主题班会
- 2025年山西省华远国际陆港集团有限公司招聘笔试参考题库含答案解析
- 江苏省盐城市东台市2024-2025学年高一上学期期末考试化学试题
- 仓库管理奖惩制度
- 酒店前台插花培训课件
- 装配式建筑产业发展现状、问题与对策分析
评论
0/150
提交评论