/=====================================================================
//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. 創建一個新的TCP協議控制塊
2. 綁定地址和端口號(port)
3. 開始監聽(listen)
4. 設置accept的回調函數
其完整代碼如下:
- void tcp_echoserver_init(void)
- {
- //創建一個新的TCP控制塊
- tcp_echoserver_pcb = tcp_new();
- if (tcp_echoserver_pcb != NULL)
- {
- err_t err;
- //綁定到端口7
- err = tcp_bind(tcp_echoserver_pcb, IP_ADDR_ANY, 7);
- if (err == ERR_OK)
- {
- //開始監聽
- tcp_echoserver_pcb = tcp_listen(tcp_echoserver_pcb);
- //設置tcp_echoserver_accept爲accept的回調函數
- tcp_accept(tcp_echoserver_pcb, tcp_echoserver_accept);
- }
- else
- {
- printf("Can not bind pcb\n"); //norains 2011-7-4 comment
- }
- }
- else
- {
- printf("Can not create new pcb\n"); //norains 2011-7-4 comment
- }
- }
當客戶端開始連接之後,那麼被設置的tcp_echoserver_accept()回調函數就會被調用。該函數主要是創建一個新的數據結構,並且將該數據結構傳遞給底層的TCP,最後分別是設置receive,error和poll這三個回調函數。
tcp_echoserver_accept()代碼如下所示:
- static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
- {
- err_t ret_err;
- struct tcp_echoserver_struct *es;
- LWIP_UNUSED_ARG(arg);
- LWIP_UNUSED_ARG(err);
- ///給新的連接設置優先級
- tcp_setprio(newpcb, TCP_PRIO_MIN);
- //分配一個結構體空間以保持TCP的連接
- es = (struct tcp_echoserver_struct *)mem_malloc(sizeof(struct tcp_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
- {
- /* return memory error */
- ret_err = ERR_MEM;
- }
- return ret_err;
- }
接下來便是tcp_echoserver_recv()這個回調函數,因爲該函數比較大,這裏就不再全部羅列代碼了。對於使用者來說,只需要知道相應的判定條件來代表什麼意思就足夠了,如:
- static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
- {
- struct tcp_echoserver_struct *es;
- err_t ret_err;
- LWIP_ASSERT("arg != NULL",arg != NULL);
- es = (struct tcp_echoserver_struct *)arg;
- if (p == NULL)
- {
- //如果接收到空的幀,則釋放連接
- ...
- }
- else if(err != ERR_OK)
- {
- //接收到一個非空的幀,但可能某些原因出錯,導致返回值不爲ERR_OK,故在此釋放緩存
- ...
- }
- else if(es->state == ES_ACCEPTED)
- {
- //連接成功,在這裏需要設置sent回調函數
- ...
- }
- else if (es->state == ES_RECEIVED)
- {
- //從客戶端收到數據
- ...
- }
- else
- {
- //當連接關閉時,還收到了數據
- ...
- }
- return ret_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
如果網絡聯通的話,測試成功將如下如下的畫面,如圖: