第一次第二次挥手
服务端收到客户端的fin包进入TCP_CLOSE_WAIT状态。即第一个挥手完成,然后服务器发送ack给客户端,即第二次挥手完成。
static int tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
{
sk->fin_seq = th->seq + skb->len + th->syn + th->fin;
if (!sk->dead)
{
sk->state_change(sk);
sock_wake_async(sk->socket, 1);
}
switch(sk->state)
{
case TCP_SYN_RECV:
case TCP_SYN_SENT:
case TCP_ESTABLISHED:
/*
* move to CLOSE_WAIT, tcp_data() already handled
* sending the ack.
*/
tcp_set_state(sk,TCP_CLOSE_WAIT);
if (th->rst)
sk->shutdown = SHUTDOWN_MASK;
break;
case TCP_CLOSE_WAIT:
case TCP_CLOSING:
/*
* received a retransmission of the FIN, do
* nothing.
*/
break;
case TCP_TIME_WAIT:
/*
* received a retransmission of the FIN,
* restart the TIME_WAIT timer.
*/
reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
return(0);
case TCP_FIN_WAIT1:
/*
* This case occurs when a simultaneous close
* happens, we must ack the received FIN and
* enter the CLOSING state.
*
* This causes a WRITE timeout, which will either
* move on to TIME_WAIT when we timeout, or resend
* the FIN properly (maybe we get rid of that annoying
* FIN lost hang). The TIME_WRITE code is already correct
* for handling this timeout.
*/
if(sk->ip_xmit_timeout != TIME_WRITE)
reset_xmit_timer(sk, TIME_WRITE, sk->rto);
tcp_set_state(sk,TCP_CLOSING);
break;
case TCP_FIN_WAIT2:
/*
* received a FIN -- send ACK and enter TIME_WAIT
*/
reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
sk->shutdown|=SHUTDOWN_MASK;
tcp_set_state(sk,TCP_TIME_WAIT);
break;
case TCP_CLOSE:
/*
* already in CLOSE
*/
break;
default:
tcp_set_state(sk,TCP_LAST_ACK);
/* Start the timers. */
reset_msl_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
return(0);
}
return(0);
}
第三次挥手
接着服务器调用close函数关闭本端的写端。
// 关闭一个socket
static void tcp_close(struct sock *sk, int timeout)
{
/*
* We need to grab some memory, and put together a FIN,
* and then put it into the queue to be sent.
*/
sk->inuse = 1;
// 监听型的socket要关闭建立的连接
if(sk->state == TCP_LISTEN)
{
/* Special case */
tcp_set_state(sk, TCP_CLOSE);
// 关闭已经建立的连接
tcp_close_pending(sk);
release_sock(sk);
return;
}
sk->keepopen = 1;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead)
sk->state_change(sk);
if (timeout == 0)
{
struct sk_buff *skb;
/*
* We need to flush the recv. buffs. We do this only on the
* descriptor close, not protocol-sourced closes, because the
* reader process may not have drained the data yet!
*/
// 销毁未处理的数据
while((skb=skb_dequeue(&sk->receive_queue))!=NULL)
kfree_skb(skb, FREE_READ);
/*
* Get rid off any half-completed packets.
*/
// 有小数据包则发送
if (sk->partial)
tcp_send_partial(sk);
}
/*
* Timeout is not the same thing - however the code likes
* to send both the same way (sigh).
*/
if(timeout)
{
tcp_set_state(sk, TCP_CLOSE); /* Dead */
}
else
{
if(tcp_close_state(sk,1)==1)
{
tcp_send_fin(sk);
}
}
release_sock(sk);
}
状态的处理逻辑在tcp_close_state函数中。由下面代码可知,当前是TCP_CLOSE_WAIT状态,即将进入LAST_ACK状态,然后发送一个fin包给客户端,即完成了第三次挥手。
// 根据socket的当前状态修改下一个状态
static int tcp_close_state(struct sock *sk, int dead)
{
// 默认状态是关闭
int ns=TCP_CLOSE;
// 默认不需要发送fin包
int send_fin=0;
switch(sk->state)
{ // 还没有建立连接,直接转为关闭状态
case TCP_SYN_SENT: /* No SYN back, no FIN needed */
break;
// 收到syn包并且发出了ack,对方也可能已经收到了ack把状态置为已建立,所以需要发送fin包,并把状态置为fin_wait1
case TCP_SYN_RECV:
case TCP_ESTABLISHED: /* Closedown begin */
ns=TCP_FIN_WAIT1;
send_fin=1;
break;
// 本端已关闭,即已经发送了fin包,不需要再发送了,状态不变
case TCP_FIN_WAIT1: /* Already closing, or FIN sent: no change */
case TCP_FIN_WAIT2:
case TCP_CLOSING:
ns=sk->state;
break;
// 直接置为关闭状态
case TCP_CLOSE:
case TCP_LISTEN:
break;
// 对端已关闭,现在是本端准备关闭,需要发送fin包,然后进入last_ack状态
case TCP_CLOSE_WAIT: /* They have FIN'd us. We send our FIN and
wait only for the ACK */
ns=TCP_LAST_ACK;
send_fin=1;
}
tcp_set_state(sk,ns);
/*
* This is a (useful) BSD violating of the RFC. There is a
* problem with TCP as specified in that the other end could
* keep a socket open forever with no application left this end.
* We use a 3 minute timeout (about the same as BSD) then kill
* our end. If they send after that then tough - BUT: long enough
* that we won't make the old 4*rto = almost no time - whoops
* reset mistake.
*/
// 如果是本端已经关闭,在等待对端关闭的状态,则设置一个定时器,如果超时还没有收到对端的fin包则强行关闭
if(dead && ns==TCP_FIN_WAIT2)
{
int timer_active=del_timer(&sk->timer);
if(timer_active)
add_timer(&sk->timer);
else
reset_msl_timer(sk, TIME_CLOSE, TCP_FIN_TIMEOUT);
}
return send_fin;
}
第四次挥手
这时候服务器socket的状态是LAST_ACK,收到客户端发送的最后ack包的时候即完成了第四次挥手,处理代码在tcp_ack中。
if (sk->state == TCP_LAST_ACK)
{
if (!sk->dead)
sk->state_change(sk);
if(sk->debug)
printk("rcv_ack_seq: %lX==%lX, acked_seq: %lX==%lX\n",
sk->rcv_ack_seq,sk->write_seq,sk->acked_seq,sk->fin_seq);
if (sk->rcv_ack_seq == sk->write_seq /*&& sk->acked_seq == sk->fin_seq*/)
{
flag |= 1;
tcp_set_state(sk,TCP_CLOSE);
sk->shutdown = SHUTDOWN_MASK;
}
}