2006-8-11 7:11:45 阅读(344) 评论(4)
前面我们讲到在实验环境中,主机1已经给主机13发送了FIN数据报的应答。该应答数据报相当简单,就只有一个ACK标志,而且它不占用序号。下面我们看看,13如何处理这个应答数据报的。
前面我们看到,13上的socket当前已处于TCP_TIME_WAIT1状态。收到FIN应答后,socket将状态标为 TCP_TIME_WAIT2,表示自己这边的半关闭已完成,开始等待对方的半关闭。同时将socket的成员sk_shutdown标为 SEND_SHUTDOWN,表示是执行主动关闭。
接下来, socket进入一个超时等待状态,如果在超时时间到达之后,还没有收到来自1的FIN数据报,则直接销毁socket,把来自1的FIN数据报留给协议栈的tcp control socket处理。
一段时间后,我们手动关闭主机1上的服务端进程,此时1会向13发送一个FIN数据报,发起4次握手的第三步,下面是数据报内容:
数据内容 含义
基本TCP首部
13 8a
阅读(344) | 评论(4) | 阅读全文>>
2006-8-10 23:02:05 阅读(480) 评论(0)
前面我们看到,建立一个TCP连接需要三次握手(SYN, SYN+ACK, ACK)。而终止一个连接要经过4次握手,下面我们会看到,严格来讲,是两个两次握手,即A端告知B端它终止从A端到B端的连接,即A端不会再往B端发送 数据了(通过向B端发送一个FIN标志)。A端的关闭即告完成,此时,我们说A到B的这条TCP连接处于半关闭状态(half-close)。
但这时,B端还是可以向A端发送数据的,B端可以在将来的任一时间内向A端发送FIN来完成它这端的半关闭。此时,A端的socket可能已经不存在(超 时删除),但A主机的TCP/IP协议栈中有一个tcp control socket会代为完成一个ACK动作,完成第二个两次握手,从而彻底断开这条TCP连接。
但在实际应用中,通常不可能一端执行半关闭后,另一端还继续发送数据,过一段时间后才完全关闭。通常是一端执行主动关闭后,另一方马上执行被动关闭。
为了清晰起见,我们建立一个实验环境.172.16.48.13(以下简称13)上运行一个TCP客户端进程,172.16.48.1(以下简称1)上运 行一个TCP的服务端进程,在端口5002上进行侦听(关于侦听,以后会介绍)。13连向1的5002端口,发送一个TCP数据报后,进程退出,执行主动 关闭,向1发送一个FIN,1进行应答,连接进入半关闭状态,但1的进程不关闭socket,直到人为关闭进程时,才向13发送FIN,13应答,TCP 连接完全关闭。
下面我们详细分析这整个流程,下面是13上的客户端进程的源代码:
#i
阅读(480) | 评论(0) | 阅读全文>>
2006-8-7 7:44:07 阅读(401) 评论(0)
TCP协议发送和接收数据报的过程还是相当的复杂的,这里,我们在完成TCP三次握手协议后,试图避开各种复杂的因素,介绍一个最为简单的TCP数据报发送流程。
跟UDP,RAW类似,函数mytcp_sendmsg负责发送TCP数据报。首先,要确定最大报文段(MSS)的长度,因为TCP需要把应用数据分割成它认为最为合适的数据块大小,然后传给IP,而不需要IP层再去进行数据报分割,我们得到的MSS是1448。
接下来我们要进行应用数据的分割,关于应用数据的结构体struct msghdr *msg的介绍,请查阅前面的文章,这里不再重复。
结构体struct sock有两个成员,sk_write_queue是一个发送队列,有一个或多个待发送的socket缓冲区struct sk_buff排队。sk_send_head指向发送队列中当前需要发送的第一个strcut sk_buff。如果sk_send_head为NULL,则表示当前队列为空,我们需要构建一个新的struct sk_buff来发送我们的应用数据,或者,如果sk_write_queue中最后一个struct sk_buff的长度已经达到MSS的值,则我们也需要构建一个新的struct sk_buff,否则我们可以把新的应用数据添加到sk_write_queue队列中最后一个struct sk_buff中。
如果要构建新的strcut sk_buff以发送数据,我们首先检查发送缓存是否还有足够的空间,struct sock的成员sk_wmem_queued记录了当前在发送缓存队列sk_write_queue中总的字
阅读(401) | 评论(0) | 阅读全文>>
2006-8-6 12:53:24 阅读(427) 评论(4)
TCP提供的是一种面向连接的,可靠的字节流服务,TCP提供可靠性的一种重要的方式就是MSS。通过MSS,应用数据被分割成TCP认为最适合发送的数 据块,由TCP传递给IP的信息单位称为报文段或段(segment)。代表一个TCP socket的结构体struct tcp_sock中有多个成员用于确定应用数据被分割成最大为多大的数据块较为合适(最大报文段长度MSS)。
我们不难联想到,跟最大报文段长度最为相关的一个参数是网络设备接口的MTU,以太网的MTU是1500,基本IP首部长度为20,TCP首部是20,所以MSS的值可达1460(MSS不包括协议首部,只包含应用数据)。
前面的TCP三次握手协议中我们看到,通讯的双方都通过TCP选项通告了自己期望接收的MSS值,该值直接来源于struct tcp_sock的成员advmss,而这个值直接取自于网络设备接口的MTU减去IP首部和TCP首部的长度。在本地以太网中可达1460(如果首部都 不含选项的话)。而成员rx_opt是一个结构体struct tcp_options_received,它记录的是来自对端的TCP选项通告,其成员mss_clamp表示mss的上限值,其来源就是对端的MSS 通告,而mss_user是用户设置的mss,其优先级最高,如果有user_mss,则使用user_mss,忽略其它。
从上面我们可以看到,MSS是可以通过SYN段进行协商的(MSS选项只能出现在SYN报文段中),但它并不是任何条件下都可以协商的,如果一方不接受来 自另一方的MSS值,并且没有user_mss,则MSS就定为默认值536字节(加上首部,允许
阅读(427) | 评论(4) | 阅读全文>>