前面我們已經學習了TCP的所有發送、接收和各種回調函數。本文將介紹最後一部分,TCP的輪詢機制。
在前面TCP發送Hello World的實例中,我們是在main函數的while循環中每隔1s調用一次數據發送函數。本文的實例將利用輪詢機制完成同樣的功能。
SDK程序設計
本文根據TCP client模式下發送hello world的程序改編(server模式改動也類似)。主要差別在user_udp.c文件中, 其餘文件代碼基本相同(main.c的while循環中無需調用send_data函數發送數據)。
#include "user_tcp.h"
#define SEND_SIZE 12
static struct tcp_pcb *connected_pcb = NULL;
int tcp_poll_cnt = 0;
char sendBuffer[12]="Hello World!";
//--------------------------------------------------
// TCP輪詢的回調函數
//--------------------------------------------------
err_t tcp_poll_callback(void * arg, struct tcp_pcb * tpcb)
{
tcp_poll_cnt++; //統計發送數據的次數
xil_printf("poll int:%d\r\n", tcp_poll_cnt);
send_data();
return ERR_OK;
}
//--------------------------------------------------
// TCP連接成功的回調函數
//--------------------------------------------------
err_t tcp_connected_callback(void *arg, struct tcp_pcb *tpcb, err_t err)
{
xil_printf("txperf: Connected to iperf server\r\n");
connected_pcb = tpcb; //存儲連接的TCP狀態
tcp_nagle_disable(connected_pcb);
tcp_arg(tpcb, NULL); //指定應該傳遞迴調函數的參數
//設置輪詢回調函數tcp_sent_callback
tcp_poll(connected_pcb, tcp_poll_callback, 2);
xil_printf("Connect Success.\r\n");
return ERR_OK;
}
//--------------------------------------------------
// TCP PCB初始化函數
//--------------------------------------------------
int tcp_send_init()
{
struct tcp_pcb *pcb;
struct ip_addr ipaddr;
err_t err;
u16_t port;
//創建新的TCP PCB
pcb = tcp_new();
if (!pcb) {
xil_printf("txperf: Error creating PCB. Out of Memory\r\n");
return -1;
}
IP4_ADDR(&ipaddr, 192, 168, 1, 100); //服務器的IP地址
port = 7; //服務器的默認端口
//連接主機,連接建立後調用回調函數tcp_connected_callback
err = tcp_connect(pcb, &ipaddr, port, tcp_connected_callback);
if (err != ERR_OK) {
xil_printf("txperf: tcp_connect returned error: %d\r\n", err);
return err;
}
xil_printf("%d\r\n",err);
return 0;
}
//--------------------------------------------------
// TCP數據發送函數
//--------------------------------------------------
void send_data(void)
{
err_t err;
struct tcp_pcb *tpcb = connected_pcb;
if (!connected_pcb)
return;
err = tcp_write(tpcb, sendBuffer, SEND_SIZE, 3);
if (err != ERR_OK) {
xil_printf("txperf: Error on tcp_write: %d\r\n", err);
connected_pcb = NULL;
return;
}
err = tcp_output(tpcb);
if (err != ERR_OK) {
xil_printf("txperf: Error on tcp_output: %d\r\n",err);
return;
}
}
在連接成功的回調函數tcp_connected_callback中,使用tcp_poll函數綁定TCP的輪詢回調函數tcp_poll_callback。當連接處於空閒狀態時(即沒有發送或接收數據),lwIP將週期性的調用輪詢回調函數。
tcp_toll指定輪詢應用程序時應調用的回調函數和輪詢間隔。TCP有一個粗略的計時器,大概一秒鐘發出兩次信號,輪詢間隔時間和此有關。此處設置爲2,則表示應用程序大約每(2/2=)1秒輪詢一次。本例在輪詢回調函數中發送數據。
這種機制類似看門狗定時器,以解決長時間處於空閒狀態的連接;也可以作爲一種等待內存變爲可用狀態的方法。比如當內存不可用導致tcp_write的調用失敗時,應用程序可以在連接空閒了一段時間後,使用輪詢功能再次調用tcp_write。
測試結果如下,串口信息中可看到進入輪詢回調函數的次數:
總結
止此,lwIP中所有與UDP、TCP相關的函數即使用方法都介紹完畢,且給出了實例的形式。希望對各位有幫助。