⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tcp.c

📁 cf8020+cp2200(网络)的驱动实现
💻 C
📖 第 1 页 / 共 2 页
字号:
   // 若报文的同步比特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 + -