學會Zynq(21)TCP輪詢機制(polling)示例

前面我們已經學習了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相關的函數即使用方法都介紹完畢,且給出了實例的形式。希望對各位有幫助。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章