STM32F2xx的tcp_echoserver例程解說
//=====================================================================
//TITLE:
// STM32F2xx的tcp_echoserver例程解說
//AUTHOR:
// norains
//DATE:
// Monday 04-July-2011
//Environment:
// Keil MDK 4.2
// STM32F207 核心版
//=====================================================================
最近拿到STM32F207的核心版,板載有網卡芯片,自然要拿過來搗鼓一番。而對于一個從未接觸過網絡的菜鳥來說,最好的入門方式就是揣測ST公司的例程,所以今天norains也不例外。那么我們就一起來看看這個官方的例程吧!
首先我們來了解C/S網絡程序的工作流程,如圖:
這個圖并不是norains所繪制的,而是網上流傳的一個名為《TCP/IP Socket網絡編程》的PPT所截取的。這個流程各位一定要熟悉,因為接下來所描述的例子流程,和該圖例非常吻合。
ST關于TCP的例程分為client和server,根據字面意思,可以知道tcp_echoserver例程是將STM32F2xx作為server來用。而例程的第一步呢,便是初始化,調用的是tcp_echoserver_init()函數。
在tcp_echoserver_init()函數里,主要做了這么幾件事情:
1. 創(chuàng)建一個新的TCP協議控制塊
2. 綁定地址和端口號(port)
3. 開始監(jiān)聽(listen)
4. 設置accept的回調函數
其完整代碼如下:
voidtcp_echoserver_init(void)
{
//創(chuàng)建一個新的TCP控制塊
tcp_echoserver_pcb=tcp_new();
if(tcp_echoserver_pcb!=NULL)
{
err_terr;
//綁定到端口7
err=tcp_bind(tcp_echoserver_pcb,IP_ADDR_ANY,7);
if(err==ERR_OK)
{
//開始監(jiān)聽
tcp_echoserver_pcb=tcp_listen(tcp_echoserver_pcb);
//設置tcp_echoserver_accept為accept的回調函數
tcp_accept(tcp_echoserver_pcb,tcp_echoserver_accept);
}
else
{
printf("Cannotbindpcbn");//norains2011-7-4comment
}
}
else
{
printf("Cannotcreatenewpcbn");//norains2011-7-4comment
}
}
當客戶端開始連接之后,那么被設置的tcp_echoserver_accept()回調函數就會被調用。該函數主要是創(chuàng)建一個新的數據結構,并且將該數據結構傳遞給底層的TCP,最后分別是設置receive,error和poll這三個回調函數。
tcp_echoserver_accept()代碼如下所示:
staticerr_ttcp_echoserver_accept(void*arg,structtcp_pcb*newpcb,err_terr)
{
err_tret_err;
structtcp_echoserver_struct*es;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
///給新的連接設置優(yōu)先級
tcp_setprio(newpcb,TCP_PRIO_MIN);
//分配一個結構體空間以保持TCP的連接
es=(structtcp_echoserver_struct*)mem_malloc(sizeof(structtcp_echoserver_struct));
if(es!=NULL)
{
es->state=ES_ACCEPTED;
es->pcb=newpcb;
es->p=NULL;
//傳遞新分配的結構體數據給新的pcb
tcp_arg(newpcb,es);
//為新的連接設置receive回調函數
tcp_recv(newpcb,tcp_echoserver_recv);
//為新的連接設置error回調函數
tcp_err(newpcb,tcp_echoserver_error);
//為新的連接設置poll回調函數
tcp_poll(newpcb,tcp_echoserver_poll,1);
ret_err=ERR_OK;
}
else
{
/*returnmemoryerror*/
ret_err=ERR_MEM;
}
returnret_err;
}
接下來便是tcp_echoserver_recv()這個回調函數,因為該函數比較大,這里就不再全部羅列代碼了。對于使用者來說,只需要知道相應的判定條件來代表什么意思就足夠了,如:
staticerr_ttcp_echoserver_recv(void*arg,structtcp_pcb*tpcb,structpbuf*p,err_terr)
{
structtcp_echoserver_struct*es;
err_tret_err;
LWIP_ASSERT("arg!=NULL",arg!=NULL);
es=(structtcp_echoserver_struct*)arg;
if(p==NULL)
{
//如果接收到空的幀,則釋放連接
...
}
elseif(err!=ERR_OK)
{
//接收到一個非空的幀,但可能某些原因出錯,導致返回值不為ERR_OK,故在此釋放緩存
...
}
elseif(es->state==ES_ACCEPTED)
{
//連接成功,在這里需要設置sent回調函數
...
}
elseif(es->state==ES_RECEIVED)
{
//從客戶端收到數據
...
}
else
{
//當連接關閉時,還收到了數據
...
}
returnret_err;
}
STM32F207的代碼部分就暫時說到這里,現在的問題是,如何測試這代碼的正確性呢?這就必須用到ST提供的echotool.exe程序了。該程序位于stm32f2x7_eth_lwip的PC_Software文件夾中。該程序必須在命令行打開,其大致參數如下所示:
如果我們的serverip地址為192.168.0.8,那么可以輸入如下命令進行測試:
echotool.exe 192.168.0.8 /p tcp /r 7 /n 15 /t 2 /d Testing LwIP TCP echo server
如果網絡聯通的話,測試成功將如下如下的畫面,如圖: