📄 tcp.c
字号:
// 若报文的同步比特SYN = 1, 此TCP Message申请新的连接,若0-4有未用连接选一个,否则把5连接做一个新的连接。
for (i=0; i < 5; i++)
{
//轮询5个连接, 其IP地址和端口为发方源地址和端口,此连接未本TCP报文的连接;
if ((ip->source_ipaddr == conxn[i].ipaddr) &&
(tcp->source_port == conxn[i].port))
{
nr = i;
// if (debug) serial_send("TCP: Rcvd msg from existing conxn\n");
break;
}
}
// If i = 5, we are not connected. If it is a SYN then assign
// a temporary conection to it for processing
if (i == 5)
{
if (tcp->flags & FLG_SYN) //SYN=1,申请新的连接,试图从0-4取一个新的连接
{
// Find first unused connection (one with IP = 0)
for (j=0; j < 5; j++)
{
if (conxn[j].ipaddr == 0)
{
nr = j;
// Initialize new connection
conxn[nr].state = STATE_LISTEN; //新连接进入Listen状态;
break;
}
}
// If all connections are used then drop msg
if (j == 5) return;
if (debug)
{
// serial_send("TCP: New connection ");
// memset(text, 10);
// itoa((uint)nr, text, 10);
// serial_send(text);
//serial_send("\n");
}
}
}
// By now we should have a connection number in range of 0-4
// Do a check to avoid any chance of exceeding size of struct
//连接数>4, 退出.
if (nr > 4)
{
if (debug)
// serial_send("TCP: Error in assigning conxn number\n");
return;
}
// Eventually put in protection against wrapping sequence
// numbers, for now make the client start over if his
// sequence number is close to wrapping 溢出
//如果收到TCP报文的发送序号 > 0xffffffoo, 为了防止溢出,向对端发送RST TCP报文,释放连接。
if (tcp->sequence > 0xFFFFFF00L)
{
// if (debug) serial_send("TCP: Rcvd a high sequence number\n");
conxn[nr].ipaddr = 0;
tcp_send(FLG_RST, 20, NO_CONNECTION);
return;
}
// Handle messages whose action is mostly independent of state
// such as RST, SYN, and segment with no ACK. That way the
// state machine below does not need to worry about it.
//如果收到TCP报文的复位比特RST=1, TCP连接出现差错,必须释放连接;
if (tcp->flags & FLG_RST)
{
// An RST does not depend on state at all. And it does
// not count as data so do not send an ACK here. Close
// connection
// if (debug)
// serial_send("TCP: Rcvd a reset\n");
conxn[nr].ipaddr = 0;//ipaddr = 0, 释放连接
return;
}
//如果收到TCP报文的同步比特SYN = 1时(表示这是一个连接请求或连接接受报文), 且连接不处于Listen或close状态
//,接收出现错误,释放连接;
else if (tcp->flags & FLG_SYN)
{
// A SYN segment only makes sense if connection is in LISTEN
if ((conxn[nr].state != STATE_LISTEN) &&
(conxn[nr].state != STATE_CLOSED))
{
// if (debug) serial_send("TCP: Error, rcvd bogus SYN\n");
conxn[nr].ipaddr = 0;
tcp_send(FLG_RST, 20, NO_CONNECTION);
return;
}
}
//如果收到TCP报文的确认比特ACK = 0,(ACK = 1, 确认号字段才有效), 且SYN和RST都等于0,
//接收出现错误,但不释放连接,只是什么事都不做;
else if ((tcp->flags & FLG_ACK) == 0)
{
// Incoming segments except SYN or RST must have ACK bit set
// See TCP/IP Illustrated, Vol 2, Page 965
// Drop segment but do not send a reset
// if (debug) serial_send("TCP: Error, rcvd segment has no ACK\n");
return;
}
// Compute length of header including options, and from that
// compute length of actual data
//计算收到TCP报文的首部长度
header_len = (tcp->flags & 0xF000) >> 10;
//计算收到TCP报文的数据长度
data_len = len - header_len;
// Handle TCP state machine for this connection
//处理TCP的有限状态机
switch (conxn[nr].state)
{
case STATE_CLOSED:
case STATE_LISTEN: //在侦听Listen状态
// If incoming segment contains SYN and no ACK, then handle
// 侦听阶段,接收申请连接: 如果收到TCP报文的同步比特SYN = 1且确认比特ACK = 0,表明对端已申请连接但未成功。
// 回传SYN和ACK的set,接收连接并填充连接信息.
if ((tcp->flags & FLG_SYN) && ((tcp->flags & FLG_ACK) == 0))
{
// Capture his starting sequence number and generate
// my starting sequence number
// Fill in connection information
conxn[nr].ipaddr = ip->source_ipaddr; //收到IP报文的源IP地址,即对端发方的IP地址
conxn[nr].port = tcp->source_port; //收到TCP报文的源端口,即对端发方的端口
conxn[nr].state = STATE_LISTEN;
conxn[nr].his_sequence = 1 + tcp->sequence; //收到TCP报文的发送序号,即对端发方的发送序号
conxn[nr].his_ack = tcp->ack_number; //收到TCP报文的确认序号,即对端发方的确认序号
// Use system clock for initial sequence number
// EA = 0;
conxn[nr].my_sequence = initial_sequence_nr; //计算本端的发送序号
initial_sequence_nr += 64000L;
// EA = 1;
// Send header options with the next message
// Since timestamps are optional and we do not use
// them, do not have to send them
// After sending the SYN ACK the client browser will
// blast me with 2 messages, an ACK, and a HTTP GET
//回传SYN和ACK的set, 确认对端的连接申请
tcp_send(FLG_SYN | FLG_ACK, 28, nr);
// My SYN flag increments my sequence number
// My sequence number is always updated to point to
// the next byte to be sent. So the incoming ack
// number should equal my sequence number
conxn[nr].my_sequence++;
conxn[nr].state = STATE_SYN_RCVD;
// if (debug) serial_send("TCP: Entered SYN RCVD state\n");
}
else //侦听状态,收到SYN和ACK的其他组合值, 接收出现错误,释放连接
{
// Sender is out of sync so send reset
conxn[nr].ipaddr = 0;
tcp_send(FLG_RST, 20, NO_CONNECTION);
}
break;
case STATE_SYN_RCVD:
// He may already be sending me data - should process it
conxn[nr].his_sequence += data_len; //连接的对端发送序号信息迭加;
conxn[nr].his_ack = tcp->ack_number; //连接的对端确认序号等于收到报文的确认号;
if (tcp->flags & FLG_FIN) //如果收到TCP报文的终止比特FIN = 1,发送ACK=1的TCP报文,转入CLOSE_WAIT 状态;
//接着发送FIN = 1和FLG_ACK = 1, 进入 LAST_ACK状态;
{
// His FIN counts as a byte of data
conxn[nr].his_sequence++;
tcp_send(FLG_ACK, 20, nr);
conxn[nr].state = STATE_CLOSE_WAIT;
// if (debug) serial_send("TCP: Entered CLOSE_WAIT state\n");
// At this point we would normally wait for the application
// to close. For now, send FIN right away.
tcp_send(FLG_FIN | FLG_ACK, 20, nr);
conxn[nr].my_sequence++; // For my FIN
conxn[nr].state = STATE_LAST_ACK;
// if (debug) serial_send("TCP: Entered LAST ACK state\n");
}
// Make sure he is ACKing my SYN
else if (tcp->ack_number == conxn[nr].my_sequence) //如果未收到FIN, 且收到TCP报文的确认号等于本连接的发送号,进入Established状态
{
conxn[nr].state = STATE_ESTABLISHED;
// if (debug) serial_send("TCP: Entered ESTABLISHED state\n");
// If sender sent data ignore it and he will resend
// Do not send response because we received no
// data... wait for client to send something to me
}
break;
case STATE_ESTABLISHED:
conxn[nr].his_ack = tcp->ack_number;//连接的对端确认号等于收到TCP报文的确认;
if (tcp->flags & FLG_FIN) //如果收到TCP报文的终止比特FIN = 1,发送ACK=1的TCP报文,转入CLOSE_WAIT 状态;
//接着发送FIN = 1和FLG_ACK = 1, 进入 LAST_ACK状态;
{
// His FIN counts as a byte of data
conxn[nr].his_sequence++;
tcp_send(FLG_ACK, 20, nr);
conxn[nr].state = STATE_CLOSE_WAIT;
// if (debug) serial_send("TCP: Entered CLOSE_WAIT state\n");
// At this point we would normally wait for the application
// to close. For now, send FIN immediately.
tcp_send(FLG_FIN | FLG_ACK, 20, nr);
conxn[nr].my_sequence++; // For my FIN
conxn[nr].state = STATE_LAST_ACK;
// if (debug) serial_send("TCP: Entered LAST ACK state\n");
}
else
if (data_len != 0) //连接建立的正常状态,而且是有发送数据
{
// Received normal TCP segment from sender with data
// Send an ACK immediately and pass the data on to
// the application
conxn[nr].his_sequence += data_len; //连接的对端发送序号迭加;
tcp_send(FLG_ACK, 20, nr); //回传ack = 1的TCP报文,告诉对端发送成功;
// Send pointer to start of TCP payload
// http_server increments my sequence number when
// sending so don't worry about it here
result = tcp_server_recv(inbuf, header_len, nr, 0, data_len); //调用上一层的TCPSERVER处理TCP报文数据段,header_len为TCP报文的首部长度
// printf(inbuf);
// Start timer to close conxn if no activity
// inactivity: 设置连接的非激活时间
conxn[nr].inactivity = INACTIVITY_TIME; //非激活时间15秒
}
else//07-07-19,add by qg,加入回应ack处理
{
if (tcp->flags & FLG_ACK)//收到数据确认帧
{
if(tcp->ack_number != conxn[nr].my_sequence)
{//如果确认号与发送号不等,就有问题了
conxn[nr].ipaddr = 0;
tcp_send(FLG_FIN, 20, NO_CONNECTION);
}
conxn[nr].inactivity = INACTIVITY_TIME; //重置激活时间15秒
}
}
break;
case STATE_CLOSE_WAIT:
// With this , should not get here
// if (debug) serial_send("TCP: Oops! Rcvd unexpected message\n");
break;
case STATE_LAST_ACK:
conxn[nr].his_ack = tcp->ack_number;
// If he ACK's my FIN then close
// 如果收到TCP报文的确认号等于连接的发送序号,对端已收完全部数据,可以关闭连接转入STATE_CLOSED状态;
if (tcp->ack_number == conxn[nr].my_sequence)
{
conxn[nr].state = STATE_CLOSED;
conxn[nr].ipaddr = 0; // Free up struct area
just_closed = TRUE;
}
break;
case STATE_FIN_WAIT_1:
// He may still be sending me data - should process it
conxn[nr].his_sequence += data_len; //连接的对端发送序号信息迭加;
conxn[nr].his_ack = tcp->ack_number; //连接的对端确认序号等于收到报文的确认号;
if (tcp->flags & FLG_FIN) //如果收到TCP报文的终止比特FIN = 1,发送ACK=1的TCP报文.如果对端收完全部数据,转入TIME_WAIT状态;
//接着进入closed状态; 否则进入closeing状态;
{
// His FIN counts as a byte of data
conxn[nr].his_sequence++;
tcp_send(FLG_ACK, 20, nr);
// If he has ACK'd my FIN then we can close connection
if (tcp->ack_number == conxn[nr].my_sequence)
{
conxn[nr].state = STATE_TIME_WAIT;
// if (debug) serial_send("TCP: Entered TIME_WAIT state\n");
conxn[nr].state = STATE_CLOSED;
conxn[nr].ipaddr = 0; // Free up connection
just_closed = TRUE;
}
else
{
// He has not ACK'd my FIN. This happens when there is a simultaneous
// close - I got his FIN but he has not yet ACK'd my FIN
conxn[nr].state = STATE_CLOSING;
// if (debug) serial_send("TCP: Entered CLOSING state\n");
}
}
else if (tcp->ack_number == conxn[nr].my_sequence) //如果未收到TCP报文的终止比特FIN = 1,且对端收完我方全部数据,转入STATE_FIN_WAIT_2状态;
{
// He has ACK'd my FIN but has not sent a FIN yet himself
conxn[nr].state = STATE_FIN_WAIT_2;
// if (debug) serial_send("TCP: Entered FIN_WAIT_2 state\n");
}
break;
case STATE_FIN_WAIT_2:
// He may still be sending me data - should process it
conxn[nr].his_sequence += data_len;
conxn[nr].his_ack = tcp->ack_number;
if (tcp->flags & FLG_FIN) //如果收到TCP报文的终止比特FIN = 1,发送ACK=1的TCP报文,转入TIME_WAIT状态;
//接着进入closed状态, 释放连接;
{
conxn[nr].his_sequence++; // For his FIN flag
tcp_send(FLG_ACK, 20, nr);
conxn[nr].state = STATE_TIME_WAIT;
// if (debug) serial_send("TCP: Entered TIME_WAIT state\n");
conxn[nr].state = STATE_CLOSED;
conxn[nr].ipaddr = 0; // Free up struct area
just_closed = TRUE;
}
break;
case STATE_TIME_WAIT:
// With this , should not get here
// if (debug) serial_send("TCP: Oops! In TIME_WAIT state\n");
break;
case STATE_CLOSING:
// Simultaneous close has happened. I have received his FIN
// but he has not yet ACK'd my FIN. Waiting for ACK.
// Will not receive data in this state
conxn[nr].his_ack = tcp->ack_number;
if (tcp->ack_number == conxn[nr].my_sequence) //如果对端收完全部数据,转入TIME_WAIT状态;接着进入closed状态;
{
conxn[nr].state = STATE_TIME_WAIT;
// if (debug) serial_send("TCP: Entered TIME_WAIT state\n");
// Do not send any response to his ACK
conxn[nr].state = STATE_CLOSED;
conxn[nr].ipaddr = 0; // Free up struct area
just_closed = TRUE;
}
break;
default:
// if (debug) serial_send("TCP: Error, no handler\n");
break;
}
// This is for debug, to see when conxn closes
if (just_closed)
{
just_closed = FALSE;
if (debug)
{
// serial_send("TCP: Closed connection ");
// memset(text, 10);
// itoa((uint)nr, text, 10);
// serial_send(text);
// serial_send("\n");
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -