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

📄 tcp.c

📁 51单片机上实现tcp/ip的源代码
💻 C
字号:
/*********************************************************************
*            Copright(c) 2004,张会福 湖南科技大学计算机学院 
*						All rights reserved.
*
*文件名称:	tcp.c
*文件标识: 
*摘    要: 在事件的驱动下,按照状态转移图进行TCP协议的处理
*
*当前版本: V1.0
*完成日期: 2004.4.1
*
*
*********************************************************************/
#define  TCP_GLOBALS
#include "net_cfg.h"

/*****************************************************************
**函数原型: 	void 	TCP1024_Init()
**入口参数: 	无
**出口参数: 	无
**返 回 值:		无
**功能说明: 	初始化任务控制块,使本地机进入listen状态并清空重发缓冲区
******************************************************************/
void TCP1024_Init()
{
	TCP1024.State=0;
	TCP1024.My_Port=MY_TCP_PORT;
	TCP1024.Send_Next=0x0000;
	Resend_Buff.EtherFrame.RecStatus=0;//表示该重发缓冲区没有数据
	
}

//==============================================================
/**********************************************************************
**函数原型:    void        Send_Reset()
**入口参数: 	无
**出口参数: 	无
**返 回 值:		无
**功能说明: 	发送TCP_RST数据报文,复位对方连接
******************************************************************/
void Send_Reset()
{ 
	uchar i;
	for(i=0;i<3;i++)
	{
		//目的网卡地址
		TxdNetBuff.EtherFrame.DestMacId[i]=RxdNetBuff.EtherFrame.SourceMacId[i];
	}
	TxdNetBuff.EtherFrame.NextProtocal=0x0800;//协议为ip协议
	TxdNetBuff.TcpFrame.SourcePort=RxdNetBuff.TcpFrame.DestPort;
	TxdNetBuff.TcpFrame.DestPort=RxdNetBuff.TcpFrame.SourcePort;
	TxdNetBuff.TcpFrame.offset=0x50;
	TxdNetBuff.TcpFrame.window=0;
	TxdNetBuff.TcpFrame.urg=0;
	TxdNetBuff.TcpFrame.Crc=0;
	TxdNetBuff.IpFrame.DestId[0]=RxdNetBuff.IpFrame.SourceIp[0];
	TxdNetBuff.IpFrame.DestId[1]=RxdNetBuff.IpFrame.SourceIp[1];
	TxdNetBuff.IpFrame.SourceIp[0]=My_Ip_Address.words[0];
	TxdNetBuff.IpFrame.SourceIp[1]=My_Ip_Address.words[1];
	TxdNetBuff.IpFrame.ttl=0;
	TxdNetBuff.IpFrame.NextProtocal=6;//tcp
	TxdNetBuff.IpFrame.Crc=20;
	TxdNetBuff.TcpFrame.Crc=CreateTcpCrc();
	Create_Ip_Frame(20,RxdNetBuff.IpFrame.SourceIp[0],RxdNetBuff.IpFrame.SourceIp[1],6);
}

/**********************************************************************
**函数原型:    void        Tcp_Listen( )
**入口参数: 	无
**出口参数: 	无
**返 回 值:	无
**功能说明: 	本地机进入listen状态,可以对TCP_SYN或TCP_FIN请求进行处理
******************************************************************/
void Tcp_Listen()
{
	uchar i;
	/*if(RxdNetBuff.TcpFrame.control&(TCP_FIN))//reset
	{Send_Reset();}			//对方不接受请求,
	else*/
	if(RxdNetBuff.TcpFrame.control&TCP_SYN)//表示这是一个请求连接
	{
		for(i=0;i<2;i++)		//对方的ip地址
		{
			TCP1024.Dest_Ip[i]=RxdNetBuff.IpFrame.SourceIp[i];
		}
		for(i=0;i<3;i++)		//对方的以太网地址或网关地址
		{
			TCP1024.Dest_Mac_Id[i]=RxdNetBuff.EtherFrame.SourceMacId[i];
		}
		TCP1024.My_Port=MY_TCP_PORT;	//本机端口
		TCP1024.Dest_Port=RxdNetBuff.TcpFrame.SourcePort;//对方端口
		TCP1024.IRS=RxdNetBuff.TcpFrame.SeqNum;			//对方的初始化顺序号
		TCP1024.Rcv_Next=RxdNetBuff.TcpFrame.SeqNum+1;	//对方的顺序号,用于确认
		TCP1024.ISS=TCP1024.Send_Next;					//我的初始化顺序号
		TCP1024.Sent_UnAck=TCP1024.ISS;					//我的未确认得序号
		TCP1024.Send_Next=TCP1024.ISS+1;				//我的顺序号,用于发送
		TCP1024.My_Wl1=RxdNetBuff.TcpFrame.SeqNum;		//seq
		TCP1024.My_Wl2=TCP1024.Send_Next;				//
		TCP1024.Rcv_Window=RxdNetBuff.TcpFrame.window;	//对方的WINDOW大小
		TCP1024.Snd_Window=1024;						//通知对方本地最大接收1024字节的包,用于流控
		TCP1024.Dest_Max_Seg_Size=560;					//默认为560
		if(RxdNetBuff.TcpFrame.offset>20)
			if(RxdNetBuff.TcpFrame.tcpdata[0]==0x02)
				if(RxdNetBuff.TcpFrame.tcpdata[1]==0x04)		//0204为最大segment选项
				{
					TCP1024.Dest_Max_Seg_Size = 
						RxdNetBuff.TcpFrame.tcpdata[2]*256+RxdNetBuff.TcpFrame.tcpdata[3];
				}
				TCP1024.My_Max_Seg_Size=1460;//本地机可以接受最大的以太网数据包
				//===========以下建立应答帧
				for(i=0;i<3;i++)//目的网卡地址
				{
					TxdNetBuff.EtherFrame.DestMacId[i]=TCP1024.Dest_Mac_Id[i];
				}
				TxdNetBuff.EtherFrame.NextProtocal=0x0800;//协议为ip协议
				TxdNetBuff.TcpFrame.SourcePort=TCP1024.My_Port;
				TxdNetBuff.TcpFrame.DestPort=TCP1024.Dest_Port;
				TxdNetBuff.TcpFrame.SeqNum=TCP1024.ISS;
				TxdNetBuff.TcpFrame.AckNum=TCP1024.Rcv_Next;
				
				TxdNetBuff.TcpFrame.offset=0x70;
				TxdNetBuff.TcpFrame.control=0x12; //syn+ack
				TxdNetBuff.TcpFrame.window=TCP1024.Snd_Window;
				TxdNetBuff.TcpFrame.urg=0;
				TxdNetBuff.TcpFrame.Crc=0;
				TxdNetBuff.IpPacket.IpPacket[20]=0x0204;//tcp选项
				TxdNetBuff.IpPacket.IpPacket[21]=TCP1024.My_Max_Seg_Size;
				TxdNetBuff.IpPacket.IpPacket[22]=0x0101;
				TxdNetBuff.IpPacket.IpPacket[23]=0x0101;
				TxdNetBuff.IpFrame.DestId[0]=TCP1024.Dest_Ip[0];
				TxdNetBuff.IpFrame.DestId[1]=TCP1024.Dest_Ip[1];
				TxdNetBuff.IpFrame.SourceIp[0]=My_Ip_Address.words[0];
				TxdNetBuff.IpFrame.SourceIp[1]=My_Ip_Address.words[1];
				TxdNetBuff.IpFrame.ttl=0;
				TxdNetBuff.IpFrame.NextProtocal=6;//tcp
				TxdNetBuff.IpFrame.Crc=28;
				TxdNetBuff.TcpFrame.Crc=CreateTcpCrc();
				Create_Ip_Frame(28,TCP1024.Dest_Ip[0],TCP1024.Dest_Ip[1],6);
				TCP1024.State=TCP_STATE_SYN_RCVD;//Tcp_SYN_Rec;
	}
	else if(RxdNetBuff.TcpFrame.control&TCP_RST)
	{
		;//无操作
	}
	else	
	{
		Send_Reset();
	}	
}
/**********************************************************************
**函数原型:    void        Delete_Socket()
**入口参数: 	无
**出口参数: 	无
**返 回 值:	无
**功能说明: 	撤销本地连接,并清空重发缓冲区
******************************************************************/
void Delete_Socket()
{
	TcpConnected=0;
	TCP1024.State=0;
	TCP1024.ISS=TCP1024.ISS+10;//
	Resend_Buff.EtherFrame.RecStatus=0;//表示该重发缓冲区没有数据
	Printf_String("Disconnect!\r\n");
}
/**********************************************************************
**函数原型:    void        Resend_Packet( )
**入口参数: 	uchar   i
**出口参数: 	无
**返 回 值:		无
**功能说明: 	重发出错的数据包
******************************************************************/
void Resend_Packet()
{
	uint ii;
	uchar xdata *txd=&TxdNetBuff;
	uchar xdata *rt;
	
	rt=&Resend_Buff.bytes.bytebuf;
	for(ii=0;ii<Resend_Buff.ResendFrame.length+4;ii++)
	{
		(*txd)=(*rt);
		rt++;
		txd++;
	}
	Send_Packet(&TxdNetBuff,Resend_Buff.ResendFrame.length);
	Resend_Buff.ResendFrame.timeout=RtTime;
}

/**********************************************************************
**函数原型:    void        Process_Resend_Buff( )
**入口参数: 	无
**出口参数: 	无
**返 回 值:		无
**功能说明: 	根据接收数据的序号以及超时时间对重发缓冲区的数据进行处理
******************************************************************/
void Process_Resend_Buff()
{
	
	if(Resend_Buff.ResendFrame.timeout>0)
		Resend_Buff.ResendFrame.timeout--;	//数据报的重发次数减一,防止TCP死锁
	if(Resend_Buff.EtherFrame.RecStatus!=0)	//表示需要重发缓冲区的数据
	{
		if(Resend_Buff.TcpFrame.SeqNum<TCP1024.Sent_UnAck)
			//下一个待发送的数据的序号应该大于TCP1024.Sent_UnAck,因为
			//tcp1024.snd_una表示上一个已发送的数据字节的序号,如果
			//重发缓冲区的数据对应的序号小于TCP1024.Sent_UnAck,则说明数据
			//已正确发送了,重发缓冲区内的备份的数据就没有用了,因此
			//这个数据包已经过期了,可以抛弃掉,将缓冲区置为无效。
		{
			Resend_Buff.ResendFrame.RtStatus=0;
		}//该缓冲区无效
		
		else if(Resend_Buff.ResendFrame.timeout==0)//超时,或重发次数到
		{//如果重发缓冲区的数据包的序号大于等于未或确认的数据序号时待发送重发
			Resend_Buff.ResendFrame.RtStatus++;//重发次数加一
			if(Resend_Buff.ResendFrame.RtStatus==TCP_MAX_RETXD)
			{	//重发TCP_MAX_RETXD次都无法正确发送时,撤销本地连接
				Delete_Socket();
			}
			else	//继续重发
				Resend_Packet();
		}
	}
}
/**********************************************************************
**函数原型:    void        Tcp_SYN_Sent( )
**入口参数: 	无
**出口参数: 	无
**返 回 值:	无
**功能说明: 	本地机主动发送SYN后,即可进入本状态,该状态下,
**        : 	可接收几种数据:tcp_rst或tcp_syn或tcp_syn+tcp_ack
******************************************************************/
void Tcp_SYN_Sent()
{
	unsigned char i;
	if(((RxdNetBuff.TcpFrame.AckNum<=TCP1024.ISS)||(RxdNetBuff.TcpFrame.AckNum>TCP1024.Send_Next))
		&&(RxdNetBuff.TcpFrame.control&TCP_ACK))
	{	//对方发回的确认号应是我的初始化序号加1,若比我的初始化序号小
		//或大于我的下一个序号,则说明对方连接出错
		if(!(RxdNetBuff.TcpFrame.control&TCP_RST))
		{//对方不接受请求
			TxdNetBuff.TcpFrame.SeqNum=RxdNetBuff.TcpFrame.AckNum;
			TxdNetBuff.TcpFrame.AckNum=0;
			TxdNetBuff.TcpFrame.control=TCP_RST;
			Send_Reset();//复位对方连接
		}
		else//对方发来复位请求,因此撤销本地的连接
		{
			Delete_Socket();
		}
	}
	else if(RxdNetBuff.TcpFrame.control&(TCP_SYN))
	{
		TCP1024.IRS=RxdNetBuff.TcpFrame.SeqNum;			//对方的初始化顺序号
		TCP1024.Rcv_Next=RxdNetBuff.TcpFrame.SeqNum+1;	//对方的顺序号,我可以用于给对方确认
		if(RxdNetBuff.TcpFrame.control&TCP_ACK)
		{
			TCP1024.Sent_UnAck=RxdNetBuff.TcpFrame.AckNum;//我的未或确认得序号
			Process_Resend_Buff();
		}
		if(TCP1024.Sent_UnAck>=TCP1024.ISS)
		{	//表示在一个由我发起的三次连接的过程中,对方已经对我的连接请求发回了确认
			TCP1024.IRS=RxdNetBuff.TcpFrame.SeqNum;
			TCP1024.Rcv_Window=RxdNetBuff.TcpFrame.window;	//对方的window大小,表示对方可以接收的最大数据包的大小
			TCP1024.Dest_Max_Seg_Size=560;//默认为560
			if(RxdNetBuff.TcpFrame.offset>20)
				if(RxdNetBuff.TcpFrame.tcpdata[0]==0x02)
					if(RxdNetBuff.TcpFrame.tcpdata[1]==0x04)//0204为最大segment选项
					{
						TCP1024.Dest_Max_Seg_Size=RxdNetBuff.TcpFrame.tcpdata[2]*256+RxdNetBuff.TcpFrame.tcpdata[3];
					}
					//发送确认
					//===========以下建立应答帧
					for(i=0;i<3;i++)//目的网卡地址
					{
						TxdNetBuff.EtherFrame.DestMacId[i]=TCP1024.Dest_Mac_Id[i];
					}
					TxdNetBuff.EtherFrame.NextProtocal=0x0800;//协议为ip协议
					TxdNetBuff.TcpFrame.SourcePort=TCP1024.My_Port;
					TxdNetBuff.TcpFrame.DestPort=TCP1024.Dest_Port;
					TxdNetBuff.TcpFrame.SeqNum=TCP1024.Send_Next;
					TxdNetBuff.TcpFrame.AckNum=TCP1024.Rcv_Next;
					TxdNetBuff.TcpFrame.offset=0x50;
					TxdNetBuff.TcpFrame.control=TCP_ACK; 
					TxdNetBuff.TcpFrame.window=TCP1024.Snd_Window;
					TxdNetBuff.TcpFrame.urg=0;
					TxdNetBuff.TcpFrame.Crc=0;
					TxdNetBuff.IpFrame.DestId[0]=TCP1024.Dest_Ip[0];
					TxdNetBuff.IpFrame.DestId[1]=TCP1024.Dest_Ip[1];
					TxdNetBuff.IpFrame.SourceIp[0]=My_Ip_Address.words[0];
					TxdNetBuff.IpFrame.SourceIp[1]=My_Ip_Address.words[1];
					TxdNetBuff.IpFrame.ttl=0;
					TxdNetBuff.IpFrame.NextProtocal=6;//tcp
					TxdNetBuff.IpFrame.Crc=20;
					TxdNetBuff.TcpFrame.Crc=CreateTcpCrc();
					Create_Ip_Frame(20,TCP1024.Dest_Ip[0],TCP1024.Dest_Ip[1],6);
					TCP1024.State=TCP_STATE_ESTABLISHED;
					TcpConnected=1;
					Printf_String("\r\nOK,connected.\r\nC:>");
		}
		else 
		{//说明对方同时发出连接请求
			TCP1024.State=TCP_STATE_SYN_RCVD;
			//===========下面建立应答帧
			for(i=0;i<3;i++)//目的网卡地址
			{
				TxdNetBuff.EtherFrame.DestMacId[i]=TCP1024.Dest_Mac_Id[i];
			}
			TxdNetBuff.EtherFrame.NextProtocal=0x0800;//以太网协议的下层协议为IP协议
			TxdNetBuff.TcpFrame.SourcePort=TCP1024.My_Port;
			TxdNetBuff.TcpFrame.DestPort=TCP1024.Dest_Port;
			TxdNetBuff.TcpFrame.SeqNum=TCP1024.Send_Next;
			TxdNetBuff.TcpFrame.AckNum=TCP1024.Rcv_Next;
			TxdNetBuff.TcpFrame.offset=0x70;
			TxdNetBuff.TcpFrame.control=TCP_ACK+TCP_SYN; //TCP_ACK+TCP_SYN
			TxdNetBuff.TcpFrame.window=TCP1024.Snd_Window;
			TxdNetBuff.TcpFrame.urg=0;
			TxdNetBuff.TcpFrame.Crc=0;
			TxdNetBuff.IpPacket.IpPacket[20]=0x0204;//有TCP选项
			TxdNetBuff.IpPacket.IpPacket[21]=TCP1024.My_Max_Seg_Size;
			TxdNetBuff.IpPacket.IpPacket[22]=0x0101;
			TxdNetBuff.IpPacket.IpPacket[23]=0x0101;
			TxdNetBuff.IpFrame.DestId[0]=TCP1024.Dest_Ip[0];
			TxdNetBuff.IpFrame.DestId[1]=TCP1024.Dest_Ip[1];
			TxdNetBuff.IpFrame.SourceIp[0]=My_Ip_Address.words[0];
			TxdNetBuff.IpFrame.SourceIp[1]=My_Ip_Address.words[1];
			TxdNetBuff.IpFrame.ttl=0;
			TxdNetBuff.IpFrame.NextProtocal=6;
			TxdNetBuff.IpFrame.Crc=28;
			TxdNetBuff.TcpFrame.Crc=CreateTcpCrc();
			Create_Ip_Frame(28,TCP1024.Dest_Ip[0],TCP1024.Dest_Ip[1],6);
		}
	}
}
/**********************************************************************
**函数原型:    void        Tcp_SYN_Rec( )
**入口参数:		无
**出口参数:		无
**返 回 值:

⌨️ 快捷键说明

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