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

📄 tcp.c

📁 51单片机加rt8019硬件平台,上web方案及详细代码
💻 C
字号:
//-----------------------------------tcp.c-----------------------------
//#define DEBUG         

#include<string.h>
#include"includes.h"


typedef enum {
	CLOSED       = 0,	// 没有连接	
	LISTEN       = 1,	// 收到被动打开;等待SYN
	SYN_SENT     = 2,	// 已经发送SYN;等待ACK
	SYN_RCVD     = 3,	// 已发送SYN+ACK;等待ACK
	ESTABLISHED  = 4,	// 连接已建立;数据传输在进行
	FIN_WAIT1    = 5,	// 第一个FIN已经发送;等ACK
	FIN_WAIT2    = 6,	// 第一个FIN的ACK已收到;等第二个FIN

	CLOSE_WAIT   = 7,	// 收到第一个FIN,已发送ACK;等待应用程序关闭
	TIME_WAIT    = 8,	// 收到第二个FIN,已发送ACK;等待2MSL超时
	LAST_ACK     = 9,	// 已发送第二个FIN;等待ACK
	CLOSING	    = 10	// 双方都已决定同时关闭
} TCPState;



ulong idata isn;
uint xdata sender_tcpport,MinePort;
static ulong xdata sender_ipaddr;
TCB xdata conn[NO_CONN];

//Options: MSS (4 bytes), NOPS (2 bytes), Selective ACK (2 bytes) 
uchar code opt[10] = {
0x02, 0x04, 0x05, 0xB4,
0x01, 0x01,
0x04, 0x02};

/*****************************************
初始化TCP
******************************************/
void init_tcp(void)
{
   memset(conn, 0, sizeof(conn)); 
   isn = 1;
}

/*****************************************
TCP发送
******************************************/
void tcp_send(uint flags, uint hdr_len, uchar cn_id)
{
	ulong idata sum, dest;
	uint idata result;

	Tcp_Header xdata * tcp;
	Ip_Header xdata * ip;
	   
	tcp = (Tcp_Header xdata *)(outbuf + 34); //14以太网头 + 20IP头
	ip = (Ip_Header xdata *)(outbuf + 14); 

	if (cn_id == NO_CONN)
	{
		tcp->source_port = MinePort;
		tcp->dest_port = sender_tcpport;
		tcp->sn = 0;
		tcp->ack_sn = 0;
		dest = sender_ipaddr;
	}
	else if (cn_id < 5)
	{
		tcp->source_port = MinePort;
		tcp->dest_port = conn[cn_id].port;
		tcp->sn = conn[cn_id].my_sn;
		tcp->ack_sn = conn[cn_id].his_sn;
		dest = conn[cn_id].ipaddr;
	}
	else
	{
		return;	  //连接数超限
	}   
	tcp->flags = (hdr_len << 10) | flags;
	tcp->window = 1024;
	tcp->checksum = 0;
	tcp->urgent_ptr = 0;
   
   // Sending SYN with header options
	if (hdr_len == 28)
	{
		memcpy(&tcp->options, opt, 8);
	}  
   
	ip->dest_ipaddr = dest;
	ip->source_ipaddr = myipaddr;		
	//伪首部源地址和目标地址 
	sum = (ulong)cksum(outbuf + 26, 8 + hdr_len);
				
	//伪首部协议,首部长度
	sum += (ulong)0x0006;
	sum += (ulong)hdr_len;

	//进位
	result = (uint)(sum + (sum >> 16));
	tcp->checksum = ~result;
	
	ip_send(outbuf, dest, TCP_TYPE, hdr_len);
	
   //(Re)start TCP retransmit timer
	conn[cn_id].timer = TCP_TIMEOUT;
}

/*****************************************
tcp重传
******************************************/
void tcp_resend(void)
{
	static uchar idata retries = 0;
	uchar idata cn_id;

   //扫描活动连接 
	for (cn_id = 0; cn_id < 5; cn_id++)
	{
		if ((conn[cn_id].ipaddr != 0) && (conn[cn_id].timer))
		{	         
			conn[cn_id].timer--;
			if (conn[cn_id].timer == 0)
			{
				if (conn[cn_id].state != ESTABLISHED)
				{
					tcp_send(FLG_RST, 20, cn_id);
					conn[cn_id].ipaddr = 0;
					return;
				}
				else
				{ 
					if (conn[cn_id].his_ack > conn[cn_id].my_sn)
					{
						tcp_send(FLG_RST, 20, cn_id);
						conn[cn_id].ipaddr = 0;
						return;
					}
					if (conn[cn_id].his_ack < conn[cn_id].my_sn)
					{
						retries++;
						if (retries <= 2)
						{
							http_server(conn[cn_id].query, 0, cn_id, 1);
							conn[cn_id].inactivity = INACTIVITY_TIME;
						}
						else
						{
							tcp_send(FLG_RST, 20, cn_id);
							conn[cn_id].ipaddr = 0;
						}
					}
				}
			}
		}
	}
}

/*****************************************
关闭不活动的连接
******************************************/
void tcp_inactivity(void)
{
	uchar idata cn_id;	   

	for (cn_id = 0; cn_id < 5; cn_id++)
	{
		if ((conn[cn_id].ipaddr != 0) && 
          (conn[cn_id].state == ESTABLISHED) &&
          (conn[cn_id].inactivity))
		{	
			conn[cn_id].inactivity--;
			if (conn[cn_id].inactivity == 0)
			{
				tcp_send((FLG_ACK | FLG_FIN), 20, cn_id);
				conn[cn_id].my_sn++;   
				conn[cn_id].state = FIN_WAIT1;
				TRACE("CONNECT CLOSED",&cn_id,1,0);	
			}
		}
	}
}
/*****************************************
查找连接
若连接已经建立返回连接1
连接没建立返回空记录0
连接已满NO_CONN
******************************************/
uchar conn_search(ulong IPSrc,uint PortSrc,uchar * cn_id)
{
   uchar i;
   for (i=0; i < NO_CONN; i++)
	{
		if( (IPSrc == conn[i].ipaddr) && (PortSrc == conn[i].port) )
		{  
         *cn_id = i; 
         return (1);
		}       
	}
   /*连接没建立查找空记录*/
   for (i=0; i < NO_CONN; i++)
	{
		if( conn[i].ipaddr == 0 )
		{ 
         *cn_id = i;  
         return (0);
		}       
	}
   /*连接已满*/
   return NO_CONN;
}

void tcp_receive(uchar xdata * inbuf, uint len)
{
   uchar cn_id,res;
   ulong idata sum=0L;
   uint idata result, head_len, data_len;
   Ip_Header xdata * ip;
   Tcp_Header xdata * tcp;

   ip  = (Ip_Header xdata *)(inbuf + 14);
   tcp = (Tcp_Header xdata *)(inbuf + 34);

   //加上伪首部计算校验和		
	sum  = (ulong)cksum(inbuf + 26, 8 + len);//伪首部源地址和目标地址	
	sum += (ulong)0x0006;                    //伪首部协议,TCP总长度
	sum += (ulong)len;                       //TCP总长度	
	result = (uint)(sum + (sum >> 16));      //进位处理 		
	if (result != 0xFFFF)                    //比较
	   return;
      
   //请求的端口不被接受
	if (tcp->dest_port != HTTP_PORT && tcp->dest_port != CUSTOM_PORT)	
	{
		tcp_send(FLG_RST, 20, NO_CONN);//修改该函数添加源端口和目的端口		
		TRACE("tcp->dest_port Err",NULL,0,0);
		return;
	}
   MinePort =  tcp->dest_port;

   res = conn_search(ip->source_ipaddr,tcp->source_port,&cn_id);
   if(res == NO_CONN)
      return;

   if( (res == 0) && (tcp->flags & FLG_SYN) )//建立连接
   {
      conn[cn_id].state = LISTEN;
      TRACE("NEW CONN ID = ",&cn_id,1,0);
   }

   if (tcp->sn > 0xFFFFFF00L) //序号太大
	{ 
		TRACE("EXCEED SN",NULL,0,0);
		conn[cn_id].ipaddr = 0;	
      conn[cn_id].state  =	CLOSED;	
		tcp_send(FLG_RST, 20, NO_CONN);
		return;		
	} 
   
   if (tcp->flags & FLG_RST)//收到RST报文
	{		 
		conn[cn_id].ipaddr = 0;
      conn[cn_id].state  =	CLOSED;
      TRACE("R: FLG_RST STATE = CLOSED",NULL,0,0); 
		return;
	}	
	else if (tcp->flags & FLG_SYN)
	{
      TRACE("R: FLG_SYN",NULL,0,0); 	
      //服务器被动打开初始态为LISTEN,收到SYN会转换到RCVD   
		if ( (conn[cn_id].state != LISTEN) && (conn[cn_id].state != CLOSED) ) //非法SYN
		{
			conn[cn_id].ipaddr = 0;
            conn[cn_id].state  =	CLOSED;			
		  	tcp_send(FLG_RST, 20, NO_CONN);
			TRACE("INVALID SYN STATE = CLOSED",NULL,0,0);
		  	return;		
		}
	}	
	else if ((tcp->flags & FLG_ACK) == 0) //除RST、SYN报文外都要设置ACK位
	{
		return;	 
	}
   //首部长度包括选项=高4位 X 4 
	head_len = (tcp->flags & 0xF000) >> 10;
	data_len = len - head_len;	
   
	switch (conn[cn_id].state)
	{
	   case CLOSED:
		case LISTEN:     
			if ((tcp->flags & FLG_SYN) && ((tcp->flags & FLG_ACK) == 0)) //收到SYN报文段
			{
				TRACE("R: SYN @LISTEN HIS_SN = ",CP &tcp->sn,4,0); 
				conn[cn_id].ipaddr  = ip->source_ipaddr;
				conn[cn_id].port    = tcp->source_port;
				conn[cn_id].state   = LISTEN;
				conn[cn_id].his_sn  = tcp->sn + 1;	   //将接收到的序号加1用作ack
				conn[cn_id].his_ack = tcp->ack_sn;          

				conn[cn_id].my_sn = isn;
				isn += 64000L;                 
	                  
				tcp_send(FLG_SYN | FLG_ACK, 28, cn_id);
	 			TRACE("T: SYN+ACK MY_SN = ",CP &conn[cn_id].my_sn,4,0);
				TRACE("T: SYN+ACK ACK_SN = ",CP &conn[cn_id].his_sn,4,0);
				conn[cn_id].my_sn++;      
				conn[cn_id].state = SYN_RCVD; 
            TRACE("STATE = SYN_RCVD",NULL,0,0); 
			}
			else 
			{         
				conn[cn_id].ipaddr = 0;
				tcp_send(FLG_RST, 20, NO_CONN);
				TRACE("T: RST @LISTEN",NULL,0,0);   
			} 
			break;

      //已发送SYN+ACK;等待ACK
		case SYN_RCVD:     
			conn[cn_id].his_sn += data_len;
			conn[cn_id].his_ack = tcp->ack_sn;
            
			if (tcp->ack_sn == conn[cn_id].my_sn) //收到ACK
			{
	         conn[cn_id].state = ESTABLISHED; 
				TRACE("R: ACK @SYN_RCVD ACK_SN = ",CP &tcp->ack_sn,4,0);
            TRACE("STATE = ESTABLISHED",NULL,0,0); 
			}
         else
         {
            tcp_send(FLG_RST, 20, NO_CONN);
         }
			break;

      //连接已建立;数据传输在进行
		case ESTABLISHED:
				 
			conn[cn_id].his_ack = tcp->ack_sn;
           
			if (tcp->flags & FLG_FIN)
			{	
				TRACE("R: FIN @ESTABLISHED",NULL,0,0);	   
				conn[cn_id].his_sn++;
//			   tcp_send(FLG_ACK, 20, cn_id);
// 	      TRACE("T: ACK @ESTABLISHED",NULL,0,0);

//				conn[cn_id].state = CLOSE_WAIT;               
//          TRACE("STATE = CLOSE_WAIT",NULL,0,0); 

				tcp_send(FLG_FIN | FLG_ACK, 20, cn_id);
            TRACE("T: FIN+ACK @ESTABLISHED",NULL,0,0);

				conn[cn_id].my_sn++;   
				conn[cn_id].state = LAST_ACK;
            TRACE("STATE = LAST_ACK",NULL,0,0); 
			}
			else if (data_len != 0)
			{				
				TRACE("data_len = ",CP &data_len,2,0);
		//		TRACE("R: DATA @ESTABLISHED DATA = ",inbuf+header_len+34,data_len);
				conn[cn_id].his_sn += data_len;
				
				tcp_send(FLG_ACK, 20, cn_id); 
				     	   
				result = http_server(inbuf, head_len, cn_id, 0);	
				TRACE("T: ACK @ESTABLISHED ACK_SN = ",CP &conn[cn_id].his_sn,4,0);

#ifdef OSCAR_DEBUG
				if(data_len < 20)	
					TRACE("TcpData = ",inbuf+head_len+34,data_len,0);
				else
					TRACE("TcpData len is too long,NO output",0,0,0);
#endif

#ifdef OSCAR_DEBUG
//			   memcpy(&outbuf, inbuf, len);//接收到数据返回
//				conn[cn_id].his_sn += data_len;
//			tcp_send(FLG_ACK | FLG_PSH, len, cn_id); 
#endif
				conn[cn_id].inactivity = INACTIVITY_TIME;
			}
			break;

      //收到第一个FIN,已发送ACK;等待应用程序关闭
		case CLOSE_WAIT:     
      
			break; 
      
      //已发送第二个FIN;等待ACK
		case LAST_ACK: 
			conn[cn_id].his_ack = tcp->ack_sn;		      
			if (tcp->ack_sn == conn[cn_id].my_sn)
			{
				TRACE("R: ACK @LAST_ACK ACK_SN =",CP &tcp->ack_sn,4,0);
				conn[cn_id].state = CLOSED;
				conn[cn_id].ipaddr = 0;
				TRACE("CONNECT CLOSED",NULL,0,0); 
			}
			break;

      //第一个FIN已经发送;等ACK
		case FIN_WAIT1:       
			conn[cn_id].his_sn += data_len;
			conn[cn_id].his_ack = tcp->ack_sn;
                  
			if (tcp->flags & FLG_FIN) //收到FIN报文
			{				
				conn[cn_id].his_sn++;
				tcp_send(FLG_ACK, 20, cn_id);          
				
				if (tcp->ack_sn == conn[cn_id].my_sn)	//收到FIN + ACK
				{
					conn[cn_id].state = TIME_WAIT;             
					conn[cn_id].state = CLOSED;
					conn[cn_id].ipaddr = 0;
					TRACE("R: FIN+ACK @FIN_WAIT1 ACK_SN = ",CP &tcp->ack_sn,4,0);
					TRACE("CONNECT CLOSED",NULL,0,0);				
				}
				else
				{				
					conn[cn_id].state = CLOSING;
					TRACE("R: FIN @FIN_WAIT1 ENTER CLOSING",NULL,0,0); 
				}
			}
			else if (tcp->ack_sn == conn[cn_id].my_sn) //收到ACK
			{        
         		conn[cn_id].state = FIN_WAIT2;
				TRACE("R: ACK @FIN_WAIT1 ACK_SN = ",CP &tcp->ack_sn,4,0);	
			}
			break;
          
      //第一个FIN的ACK已收到;等第二个FIN
		case FIN_WAIT2:      
			conn[cn_id].his_sn += data_len;
			conn[cn_id].his_ack = tcp->ack_sn;
      
			if (tcp->flags & FLG_FIN)
			{
				conn[cn_id].his_sn++; 
				tcp_send(FLG_ACK, 20, cn_id);
				conn[cn_id].state = TIME_WAIT;		
				conn[cn_id].state = CLOSED;
				conn[cn_id].ipaddr = 0;
				TRACE("R: FIN @FIN_WAIT2  SEND:ACK_SN = ",CP &conn[cn_id].his_sn,4,0); 			
		   }
		   break;
                        
      //收到第二个FIN,已发送ACK;等待2MSL超时      
		case TIME_WAIT:
			break;
      
		case CLOSING:
			conn[cn_id].his_ack = tcp->ack_sn;      		
			if (tcp->ack_sn == conn[cn_id].my_sn)
			{
		   	conn[cn_id].state = TIME_WAIT;
				conn[cn_id].state = CLOSED;
				conn[cn_id].ipaddr = 0;  // Free up struct area
				TRACE("R: ACK @CLOSING",CP &tcp->ack_sn,4,0);
				TRACE("CONNECT CLOSED",NULL,0,0); 				
			}
			break;       
		default:
      	break;
   }      

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -