分类: LINUX
2008-11-24 09:13:17
我们上一节讲到了客户端请求到达服务器中的tcp_v4_conn_request()函数中时,服务器会给客户端发送一个ack,“第二次握手”的内容我们在上节中提到放在本文中完成,我们在tcp_v4_conn_request()函数中看到“第二次握手”是由__tcp_v4_send_synack()函数完成的
|
我们看到根据我们客户端的requst_sock结构得到inet_request_sock结构指针变量ireq,这个结构体我们在上一节http://blog.chinaunix.net/u2/64681/showart.php?id=1657954 中看到了。我们在上一节的tcp_v4_conn_request()函数中看到了取得路由的相关信息
dst = inet_csk_route_req(sk, req),在那个函数中会调用ip_route_output_flow()来查找路由表并且得到路由的信息,ip_route_output_flow()函数我们在第8节http://blog.chinaunix.net/u2/64681/showart.php?id=1408613 的文章末尾处看到了,在那里我们还并没有深入探讨路由的一些细节,但是在将来我们会再次具体的分析这里。所以这里还是围绕着主线继续往下看,我们看到在上边的__tcp_v4_send_synack()函数中再次看一下路由信息是否已经找到了,如果没有的话再次调用inet_csk_route_req()查找,如果还是没有找到就不能进行下去了。接下来要调用tcp_make_synack()函数准备一个SYN的ack包
|
这个函数我们就不细加分析了,总体来说是为“应答”的第二次握手准备一个skb数据结构,然后设置其相应的tcp头信息,我们看到其tcp的头设置了
th->syn = 1;
th->ack = 1;
当然还有路由信息也进行了设置,我们不细看了,继续往下看__tcp_v4_send_synack()函数中的代码,通过tcp_v4_check()计算并设置检验和后进入了ip_build_and_send_pkt()来建立ip头并发送数据包
|
关于ip头的具体设置请朋友们自己阅读,函数最后ip_local_out()这个函数我们在第12节http://blog.chinaunix.net/u2/64681/showart.php?id=1420186 ,具体过程就象客户端开始向服务器端发送的过程是一样的,一样会从硬件网卡发向客户端的网卡,客户端的过程类似于我们上面看到的服务器的sock过程一样,同样会在客户端的sock过程中进入tcp_v4_do_rcv()函数,具体的进入过程完全与我们的前面四节,从第14节http://blog.chinaunix.net/u2/64681/showart.php?id=1432417 开始分析的客户端到服务器端的过程相似,只不过这次是从服务器端的应答ack数据包到客户端的过程,我们不再具体描述如何进入tcp_v4_do_rcv()的函数过程,所以请朋友们参考前面四节的过程,只不过这次的运行过程在客户端的机器上,而不是服务器本身了。所以我们下边的分析仅限于客户端的linux内核的过程,请朋友们注意,我们假设客户端和服务器端都是一样的内核版本,即
在tcp_v4_do_rcv()函数中会调用tcp_rcv_state_process()来处理接收到的数据包,我们假设客户端已经接收到了服务器的ack数据包,我们只关心与我们的过程相关部分代码
|
在第9节http://blog.chinaunix.net/u2/64681/showart.php?id=1411408 tcp_v4_connect()函数的代码中我们曾经看到
tcp_set_state(sk, TCP_SYN_SENT);
将客户端的sock设置为了TCP_SYN_SENT的发送状态,所以客户端在接收到服务器端的ack包时会进入tcp_rcv_synsent_state_process()函数,函数的代码非常的长,我们不列出了,在这个函数中客户端会重新准备一个第三次握手的数据包然后调用tcp_send_ack()函数向服务器端发出“第三次握手”, tcp_send_ack()函数最终会调用tcp_transmit_skb()函数发送出去,而tcp_transmit_skb()函数我们在第11节http://blog.chinaunix.net/u2/64681/showart.php?id=1415963 那篇中分析过了。这里我们就不详细探讨过程,先请朋友们对其有一个总体的了解,我们在将来的还会再详细的探讨这段过程。