?? tcp.c
字號:
/*********************************************************************
* Copright(c) 2003,廣州周立功單片機發展有限公司
* All rights reserved.
*
*文件名稱: tcp.c
*文件標識:
*摘 要: 在事件的驅動下,按照狀態轉移圖進行TCP協議的處理
*
*當前版本: V1.0
*完成日期: 2003.2.28
*
*
*********************************************************************/
#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 + -