楊文斌
2008-9-1
一、 總則
本文件是嵌入式TCP/IP協(xié)議棧的說明文件,嵌入式TCP/IP應(yīng)用開發(fā)人員可通過閱讀本文件,掌握在嵌入式TCP/IP協(xié)議棧的基礎(chǔ)上開發(fā)服務(wù)器和客戶端應(yīng)用程序,如FTP服務(wù)器,WEB服務(wù)器,串口服務(wù)器等等。
二、 參考文件
1) TCP_IP詳解卷1,2,3
2) RFC 959 (rfc959) - File Transfer Protocol.htm
3) rfc1945- Hypertext Transfer Protocol -- HTTP/1.0
三、 技術(shù)說明
1) 用戶應(yīng)用協(xié)議棧則需要編寫以太網(wǎng)的數(shù)據(jù)報收發(fā)驅(qū)動,就可以使用協(xié)議棧提供的標(biāo)準(zhǔn)SOCKET API,完成服務(wù)器和客戶端應(yīng)用程序的開發(fā)。
2) 協(xié)議棧運(yùn)行于非操作系統(tǒng)的環(huán)境下,因此它的運(yùn)行速度與一般采用多任務(wù)操作系統(tǒng)的TCP/IP協(xié)議,速度相對說來要快。
3) 協(xié)議棧完成的功能包括ARP,IP,ICMP(ping),TCP,UDP,暫不支持IGMP,RARP。
4) 協(xié)議棧采用C代碼編寫,可方便的移植于各種單片機(jī)平臺。
5) 協(xié)議棧在ARM7+RTL8019硬件環(huán)境下測試,并建立了FTP服務(wù)器和WEB服務(wù)器,性能穩(wěn)定。
6) 協(xié)議棧建立的FTP服務(wù)器和WEB服務(wù)器與Internet Explorer瀏覽器和ftp.exe相互兼容。
7) 協(xié)議棧每一個SOCKET上建了數(shù)據(jù)緩沖隊列(數(shù)據(jù)結(jié)構(gòu)),用于接收SOCKET的并發(fā)數(shù)據(jù),實現(xiàn)多SOCKET的并發(fā)數(shù)據(jù)報處理,可同時運(yùn)行FTP服務(wù)器和WEB服務(wù)器。
8) 協(xié)議棧實現(xiàn)了ACK的延時答應(yīng)(200ms),支持TCP多包發(fā)送和接收,但未支持TCP數(shù)據(jù)報的失序處理,因此適合局域網(wǎng)內(nèi)使用。
四、 SOCKET API函數(shù)
1) 函數(shù)SOCKET * socket(u16 af,u16 type,u16 protocol)
本函數(shù)功能是從SOCKET pool中分配一個SOCKET插口,供應(yīng)用程序使用,其參數(shù)說明如下:
1. 參數(shù)af,type—無意義,保留為擴(kuò)充功能使用。
2. 參數(shù)protocol—為分配SOCKET的類型,包括TCP_PROTOCOL和UDP_PROTOCOL兩個類型。
3. 返回值:函數(shù)執(zhí)行成功,返回SOCKET*指針指向一個SOCKET,失敗返回NULL
2) 函數(shù)u16 bind(SOCKET * sock,struct sockaddr * address,u8 len)
本函數(shù)功能是將IP地址和端口綁定到一個SOCKET 指針* sock指向的SOCKET。
1. SOCKET * sock—指向被綁定的SOCKET。
2. struct sockaddr * address—指向IP地址和端口。
3. len—無意義,保留為擴(kuò)充功能使用。
4. 返回值:SUCC。
3) 函數(shù)u16 listen(SOCKET * sock, u16 QTY)
本函數(shù)功能是啟動被綁定了地址和端口的 SOCKET * sock,觸發(fā)其為監(jiān)聽狀態(tài)。本函數(shù)由服務(wù)器端應(yīng)用程序使用。
1. SOCKET * sock—指向被bind的SOCKET。
2. 返回值:SUCC。
4) 函數(shù)u16 connect(SOCKET * sock, struct sockaddr * sevaddr,u8 len)
本函數(shù)功能是用于建立一個連接,到服務(wù)器,服務(wù)器的地址和端口由參數(shù)sevaddr指定。該函數(shù)由客戶端使用。
1. SOCKET * sock—指向被連接的本地SOCKET。
2. struct sockaddr * sevaddr,-- 服務(wù)器的地址和端口.
3. u8 len—無意義,保留為擴(kuò)充功能使用。
4. 返回值:是SOCKET句柄。
5) 函數(shù)u16 accept(SOCKET * sock,struct sockaddr * address,u16 *iii)
本函數(shù)返回一個已連接的SOCKET句柄,供函數(shù)recv(),send()收發(fā)數(shù)據(jù)使用。
1. SOCKET * sock—指向一個被綁定地址和端口的SOCKET
2. struct sockaddr * address,u16 *iii--無意義,保留為擴(kuò)充功能使用。
3. 返回值:是SOCKET句柄。
6) 函數(shù)u16 recv(u16 handle,u8 * rec_buff,u16 len,u16 i)
指定句柄讀取數(shù)據(jù),由TCP使用
1. u16 handle--指定句柄
2. u8 * rec_buff—緩沖區(qū)首地址
3. u16 len—讀取數(shù)據(jù)的長度
4. u16 i--無意義,保留為擴(kuò)充功能使用。
5. 返回值:為已讀取的字節(jié)數(shù)
7) 函數(shù)u8 send(u16 handle,u8 *rec_buff,u16 len,u16 i)
向指定句柄發(fā)送數(shù)據(jù),由TCP使用
1. u16 handle--指定句柄
2. u8 * rec_buff—緩沖區(qū)首地址
3. u16 len—發(fā)送數(shù)據(jù)的長度
4. u16 i--無意義,保留為擴(kuò)充功能使用。
5. 返回值:是SUCC
8) void close(u16 handle)
發(fā)送FIN主動關(guān)閉一個SOCKET連接,handle為被關(guān)閉連接的句柄。
9) 函數(shù)u16 recvfrom(SOCKET *sock,u8 *rec_buff,u16 len,u8 i,struct sockaddr * address,u16 *addr_len)
從指定SOCKET *sock插口讀取數(shù)據(jù),由UDP使用,函數(shù)的參數(shù)具體情況如下:
1. SOCKET *sock --指向插口的指針
2. u8 * rec_buff—緩沖區(qū)首地址
3. u16 len—讀取數(shù)據(jù)的長度
4. u16 i--無意義,保留為擴(kuò)充功能使用。
5. 返回值:為已讀取的字節(jié)數(shù)
10) 函數(shù)u16 sendto(SOCKET *sock,u8 *rec_buff,u16 len,u8 i,struct sockaddr * address,u16 *addr_len)
向從指定SOCKET *sock插口發(fā)送數(shù)據(jù),由UDP使用,函數(shù)的參數(shù)具體情況如下:
1. SOCKET *sock,--指向插口的指針
2. u8 * rec_buff—緩沖區(qū)首地址
3. u16 len—發(fā)送數(shù)據(jù)的長度
4. u16 i--無意義,保留為擴(kuò)充功能使用
5. 返回值:為SUCC
五、 SOCKET API應(yīng)用舉例
1) 簡單WEB服務(wù)器--通過函數(shù)TCP_TEST()完成設(shè)置本地TCP服備器的IP地址,其過程如下:
1. 調(diào)用SOCKET API函數(shù)socket(0,0,TCP_PROTOCOL)分配一個SOCKET,
2. 調(diào)用SOCKET API函數(shù)將TCP server的IP地址與SOCKET綁定,調(diào)用函數(shù)bind()起動監(jiān)聽。
3. 函數(shù)TCP_TEST()通過函數(shù)accept()接收網(wǎng)頁獲取請求,調(diào)用函數(shù)recv()接收HTTP命令,根據(jù)命令調(diào)用函數(shù)send()發(fā)送http網(wǎng)頁。
WEB服務(wù)器程序清單
/*****************************************************
* 名稱:TCP_TEST()
* 功能:設(shè)置TCP模塊
* 入口:無
* 出口: 無
****************************************************************************/
void TCP_SETUP(void)
{
/*設(shè)置本地TCP服備器的IP地址*/
TCP_serveraddr.sin_family = 0;
TCP_serveraddr.sin_addr[0] = MY_IP_ADD[0];
TCP_serveraddr.sin_addr[1] = MY_IP_ADD[1];
TCP_serveraddr.sin_addr[2] = MY_IP_ADD[2];
TCP_serveraddr.sin_addr[3] = MY_IP_ADD[3];
TCP_serveraddr.sin_port = 80;
/*將TCP server的IP地址與SOCKET綁定*/
t = socket(0,0,TCP_PROTOCOL);
iii=bind(t,&TCP_serveraddr,sizeof(TCP_serveraddr));
iii=listen(t,4);
}
/****************************************************************************
* 名稱:TCP_TEST()
* 功能:TCP打開網(wǎng)頁測試
* 入口:無
* 出口: 無
****************************************************************************/
void TCP_TEST(void)
{
temp = accept(t,&TCP_clientaddr,&iii);/*accept網(wǎng)頁獲取請求*/
if(temp != 0xffff)
{ templen = recv(temp,TCP_rec_buff,1024,0);
if(TCP_rec_buff[5] == ' ')
{ send(temp,httpweb,169,0); /*發(fā)送http網(wǎng)頁*/
send(temp,web,395,0);
}
else if(TCP_rec_buff[5] == '1')
{
send(temp,httpgif,169,0); /*發(fā)送GIF,BMP圖片背景*/
send(temp,bmp,442,0);
}
close(temp);
}
}
2) 簡單UDP服務(wù)器—通過函數(shù)UDP_TEST()完成設(shè)置本地UDP服備器的IP地址和遠(yuǎn)端口服務(wù)器的IP地址, 其過程如下:
1. 調(diào)用SOCKET API函數(shù)socket(0,0,TCP_PROTOCOL)分配一個SOCKET
2. 調(diào)用SOCKET API函數(shù)bind()將UDP server的IP地址與SOCKET綁定,將調(diào)用SOCKET API函數(shù)enable_a_port_listen(1025)起動監(jiān)聽。
3. 函數(shù)UDP_TEST()通過函數(shù)recfrom()接收UDP數(shù)據(jù)報,接收到的UDP數(shù)據(jù)報調(diào)用SOCKET API函數(shù)sendto()回傳遠(yuǎn)程服務(wù)器。
UDP服務(wù)器程序清單
/****************************************************************************
* 名稱:UDP_SETUP()
* 功能:設(shè)置UDP模塊
* 入口:無
* 出口: 無
****************************************************************************/
void UDP_SETUP(void)
{
serveraddr.sin_family = 0; /*設(shè)置遠(yuǎn)端服務(wù)器的IP地址*/
serveraddr.sin_addr[0] = 192;
serveraddr.sin_addr[1] = 168;
serveraddr.sin_addr[2] = 0;
serveraddr.sin_addr[3] = 1;
serveraddr.sin_port = 1026;
s = socket(0,0,UDP_PROTOCOL);
clientaddr.sin_family = 0; /*設(shè)置本地UDP客戶端的IP地址*/
clientaddr.sin_addr[0] = MY_IP_ADD[0];
clientaddr.sin_addr[1] = MY_IP_ADD[1];
clientaddr.sin_addr[2] = MY_IP_ADD[2];
clientaddr.sin_addr[3] = MY_IP_ADD[3];
clientaddr.sin_port = 1025;
/*將本地IP地址與SOCKET綁定*/
iii=bind(s,&clientaddr,sizeof(clientaddr));
enable_a_port_listen(1025);
}
/****************************************************************************
* 名稱:UDP_TEST()
* 功能:UCP數(shù)據(jù)報收發(fā)測試
* 入口:無
* 出口: 無
****************************************************************************/
void UDP_TEST(void)
{
/*接收UDP數(shù)據(jù)報*/
len = recvfrom(s,rec_buff,400,0,&serveraddr,&iii);
if(len > 0)
{ /*將接收到的UDP數(shù)據(jù)報發(fā)送回服務(wù)器端*/
sendto(s,rec_buff,len,0,&serveraddr,&iii);
}
}