久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 21108|回復: 1
打印 上一主題 下一主題
收起左側

lwip的回調函數學習筆記與相關函數釋疑

[復制鏈接]
跳轉到指定樓層
樓主
ID:91350 發表于 2015-9-30 12:45 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式


    ETH_BSP_Config();  //硬件外設初始化

    LwIP_Init();//ip地址 網關等初始化



udp_test_init();//使用udp協議時的相關初始化









void udp_test_init(void)

{

    struct udp_pcb *pcb;//定義udp協議指針

    pcb = udp_new();//新建一個 并開辟空間內存

    udp_bind(pcb,IP_ADDR_ANY,2000);//分配IP等

    udp_recv(pcb,Udp_Test_Receive,NULL);//將回調函數賦給指針  這個函數中 將回調函數Udp_Test_Receive作為參數傳給udp_recv,實際表達的作用就是 這樣

// pcb->recv = Udp_Test_Receive

//  pcb->recv_arg = 空;

}

   Udp_pcb是一個自帶鏈表的的結構體,

struct udp_pcb {

/* Common members of all PCB types */

  IP_PCB;



/* Protocol specific PCB members */



  struct udp_pcb *next;



  u8_t flags;

  /** ports are in host byte order */

  u16_t local_port, remote_port;



#if LWIP_IGMP

  /** outgoing network interface for multicast packets */

  ip_addr_t multicast_ip;

#endif /* LWIP_IGMP */



#if LWIP_UDPLITE

  /** used for UDP_LITE only */

  u16_t chksum_len_rx, chksum_len_tx;

#endif /* LWIP_UDPLITE */



  /** receive callback function */

  udp_recv_fn recv;

  /** user-supplied argument for the recv callback */

  void *recv_arg;

};



有*next,是為了可以和多個客戶端鏈接,每個鏈表都有ip,可以儲存不同端口。





仔細分析一下回調函數的作用
void Udp_Test_Receive(void *arg,struct udp_pcb *pcb,struct pbuf *p,struct ip_addr *addr,u16_t port)

{

    //struct ip_addr destAddr = *addr;

    //unsigned char g_tData[256];

    struct pbuf *p1;

    unsigned char *nptr;           //指向UDP接收緩存區的指針

    short len;                                         //接收到的UDP數據包長度

    unsigned short LenUpdata = 0;  //升級數據包的有效數據長度

    unsigned char ret,saddr;



    if(p != NULL)

    {



        len = p->len;

        len = len;

        nptr = (unsigned char*)p->payload;

/////////////////////////////////////////////////////////////////

Add  your  code here

////////////////////////////////////////////////////////////////

  pbuf_free(p);//釋放

}







使用回調函數實際上就是在調用某個函數(通常是API函數)時,將自己的一個函數(這個函數為回調函數)的地址作為參數傳遞給那個函數。而那個函數在需要的時候,利用傳遞的地址調用回調函數,這時你可以利用這個機會在回調函數中處理消息或完成一定的操作。

回調函數只初始化一次就表明以后來數據就只調用該一個回調函數。

其它函數解釋



struct tcp_pcb *tcp_new(void)

創建一個新的連接標識符(PCB)。如果沒有有效的存儲空間創建這個新的pcb,返回NULL。

譯注:這個函數創建一個TCP協議控制塊,但并不把它放到任何TCP PCB列表,直到使用tcp_bind()函數綁定。Tcp_new()函數會調用tcp_alloc函數來動態申請一塊內存并初始化它,之后將這塊內存的首地址返回給tcp_new()函數,如果動態內存不成功的話返回NULL。

err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,

u16_t port)

給pcb綁定一個本地IP地址和端口號。如果參數"ipaddr"為IP_ADDR_ANY,則為這個pcb綁定任意本地IP地址。

譯注:這個函數的大部分代碼用于檢驗給出的IP地址和端口號是否合適,如果合適則將給出的IP地址和端口號賦給當前PCB,更新已綁定tcp_pcb列表并返回ERR_OK.如果給出的參數不合適,則返回ERR_USE(表示端口已被使用)。

參數ipaddr如果為IP_ADDR_ANY,表示綁定到任意本地地址,那么IP_ADDR_ANY是什么呢?在lwip-1.3.0\src\include\ipv4\lwip\ip_addr.h中定義了:

#define IP_ADDR_ANY         ((struct ip_addr *)&ip_addr_any)



ip_addr_any是一個ip_addr型變量,在lwip-1.3.0\src\core\ipv4\ip_addr.c中有如下聲明:

                #define IP_ADDR_ANY_VALUE 0x00000000UL

const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };

所以, IP_ADDR_ANY是等于0x00000000UL的. 在IP地址上規定  0.0.0.0為廣播地址,也就是任意地址的意思。



分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:91350 發表于 2015-9-30 12:46 | 只看該作者

- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)

指定一個PCB進入監聽狀態。當一個遠端連接訪問時,函數 tcp_accept()指定的回調函數將被調用。在調用這個函數之前一定要使用tcp_bind()函數綁定一個本地IP和端口號。

 tcp_listen() 函數返回一個新的連接標識符,原始的pcb會被釋放,這是為了節省內存,使之更適合小內存系統。

如果監聽連接的內存無效,tcp_listen()函數返回NULL,如果這樣的話,傳入的PCB參數將不會被釋放。

這個函數從原理上看也比較簡單,首先是做一些必要的檢查,判斷原始pcb是否已經處于連接狀態,如果沒有則申請一塊tcp_pcb類型的內存,將原始的必要的pcb內容復制到新的pcb,設置新的pcb狀態為LISTEN,釋放原始的pcb,并將新pcb連接放入已監聽隊列。

 

- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)

這個函數和tcp_listen()函數相同,只是限制了TCP監聽隊列連接個數,這個個數由backlog參數指定。為了使用它,你必須在你的lwipopt.h中設置TCP_LISTEN_BACKLOG=1

 

- void tcp_accepted(struct tcp_pcb *pcb)

通知lwIP一個傳入的連接已經被接受。通常這個函數在“accept()”函數的回調函數中被調用。這允許lwIP處理自身內部的任務。比如,允許更多傳入的連接進入監聽隊列。

- void tcp_accept(struct tcp_pcb *pcb,

err_t (* accept)(void *arg, struct tcp_pcb *newpcb,

err_t err))

指定應在偵聽連接上的一個新的連接到達時調用的回調函數。

 

- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,

u16_t port, err_t (* connected)(void *arg,

struct tcp_pcb *tpcb,

err_t err));

設置打開連接的pcb連接到遠程主機并發送初始的SYN段。

函數tcp_connect() 會立即返回;它并不等待這個連接是否被正確設置。相反的,當連接正確建立后它將調用第四個參數("connected"參數)指定的函數。如果這個連接不能正確的建立,可能是主機拒絕這個連接或者主機沒有響應,"connected"函數將被調用并設置一個相應的參數。

當入隊的SYN段內存不可用時,tcp_connect()函數能返回ERR_MEM,表示連接沒有正確建立。如果SYN成功入隊,tcp_connect()函數返回ERR_OK

 

 

---TCP數據發送函數

 

lwIP會調用tcp_write()函數來發送隊列中的數據。當數據成功的發送到遠程主機,會調用一個指定的回調函數來通知應用程序。

 

- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len,

u8_t copy)

參數"dataptr"指向數據隊列;參數"len"傳遞數據的長度;參數"copy"的值為0或者1,表明是否需要申請新的內存用于數據的拷貝。如果這個參數為0,則不需要申請新的內存,此時數據只能使用指針來引用。

 如果數據長度超過當前發送緩存字節數或者要發送的段隊列長度超過lwipopts.h中定義的上限值,tcp_write()函數執行失敗并返回ERR_MEN。可以使用tcp_sndbuf()函數來返回輸出隊列有效的字節數。

使用這個函數的正確方法是根據tcp_sndbuf() 函數返回的字節數來發送數據。如果函數返回ERR_MEM,應用程序應該等待直到當前隊列數據成功的被遠程主機收到然后嘗試重新發送一次。

 

- void tcp_sent(struct tcp_pcb *pcb,

err_t (* sent)(void *arg, struct tcp_pcb *tpcb,

u16_t len))

當遠程主機成功接收(也就是應答信號)到數據時,該函數指定的回調函數被調用。傳送給回調函數的"len"參數給出了上一次已經被確認的發送的最大字節數。

 

 

--TCP數據接收函數

TCP數據接收是基于回調函數的---當一個新的數據接收到時,應用程序指定的回調函數被調用。當應用程序接收到數據后,它必須調用tcp_recved()函數來指示接收數據的大小。

 

- void tcp_recv(struct tcp_pcb *pcb,

err_t (* recv)(void *arg, struct tcp_pcb *tpcb,

struct pbuf *p, err_t err))

當接收到數據時,本函數設置的回調函數將被調用。如果傳遞給回調函數一個NULL pbuf則說明遠程主機關閉了這個連接。如果函數正常運行并且回調函數返回ERR_OK,則必須釋放這個pbuf,如果其它情況,必須保存這個pbuf,這樣才能讓lwIP內核保存它以供應用程序檢查并恢復錯誤。

 

- void tcp_recved(struct tcp_pcb *pcb, u16_t len)

當應用程序接收到數據后必須調用這個函數。參數"len"表明接收到的數據的長度。

 

 

--- 應用程序輪詢函數

當一個連接空的時候(也就是說,既沒有數據接收也沒有數據發送)lwIP會通過調用一個指定的回調函數來重復輪詢應用程序。這可以用作一個看門狗定時器,用來終止空閑時間太長的連接;或者用作等待內存有效的一種方法。舉例來說,如果調用tcp_write()函數時因為內存無效而失敗,應用程序可以使用輪詢功能在連接空閑的時候再次調用tcp_write()

 

- void tcp_poll(struct tcp_pcb *pcb, u8_t interval,

err_t (* poll)(void *arg, struct tcp_pcb *tpcb))

指定輪詢間隔和應用程序輪詢時調用的回調函數。這個間隔是以TCP粗粒度定時器為單位的,即500毫秒一次。如果參數"interval"的值為10,則意味著每5秒輪詢一次應用程序。

 

 

---關閉和終止連接函數

 

- err_t tcp_close(struct tcp_pcb *pcb)

關閉連接。如果關閉的連接內存無效,函數返回ERR_MEM,如果是這樣的話,應用程序應該等待并通過使用acknowledgment回調函數或者輪詢功能重新關閉連接。如果連接關閉成功,函數返回WRR_OK

TCP內核調用tcp_close()后,參數"pcb"指定的連接被解除。

 

- void tcp_abort(struct tcp_pcb *pcb)

通過向遠程主機發送一個RST(復位)段來終止連接。這個函數從不會失敗。

如果這個連接因為一個錯誤而被終止,則應用程序可以通過err回調函數靈活的處理這個事件。通常一個連接因錯誤而終止的原因是內存不足。這時使用tcp_err()函數設置的回調函數被調用。

 

- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,

err_t err))

指定一個處理錯誤的回調函數,該回調函數不能得到本函數的"pcb"作為它的參數,因為這個pcb可能已經被解除。

 

--- 低層次TCP接口

在系統的較低層,TCP提供一個簡單的接口。在系統初始化的時候,任何其他TCP函數被調用之前必須先調用tcp_init()函數。當系統已經運行,兩個定時器函數tcp_fasttmr() tcp_slowtmr()必須定期被調用。tcp_fasttmr()函數必須每隔TCP_FAST_INTERVAL(定義在tcp.h中)個毫秒被調用一次,tcp_slowtmr() 函數必須每隔TCP_SLOW_INTERVAL個毫秒被調用一次。

 

 

--- UDP 接口

相比之下,UDP接口要比TCP接口類似,但UDP在低層次的復雜程度上明顯比TCP簡單。

 

- struct udp_pcb *udp_new(void)ige

創建一個用于UDP通訊的UDP pcb。這個pcb直到綁定本地地址或者連接到遠程地址后才被激活。

 

- void udp_remove(struct udp_pcb *pcb)

刪除一個指定的連接。

 

-err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)

       pcb綁定一個本地地址。參數"ipaddr"IP_ADDR_ANY時,指定可以監聽任何本地IP地址。這個函數一般都會返回ERR_OK

 

- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)

       設置pcb連接到遠程主機。這個函數不產生任何流量,僅設置pcb的遠程地址。

 

- err_t udp_disconnect(struct udp_pcb *pcb)

       刪除遠程端的pcb。這個函數不產生任何流量,近視刪除pcb的遠程地址。

 

- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)

       發送pbuf結構指針p指向的數據。這個pbuf不會被釋放。

 

- void udp_recv(struct udp_pcb *pcb,

void (* recv)(void *arg, struct udp_pcb *upcb,

struct pbuf *p, struct

ip_addr *addr,

u16_t port),

void *recv_arg)

當接收到一個數據包后,該函數指定的回調函數將被調用。

 

 

---系統初始化

       一個完整通用的lwIP初始化步驟是不可能實現的,因為它還取決于配置文件(lwipopts.h)的編寫以及初始化額外運行時的環境(例如硬件定時器)。

當你使用RAW API時,我們可以給你一些建議。

我們假設你使用一個單一的以太網netifUDPTCP傳輸層、IPv4DHCP客戶端。

安以下順序調用這些函數:

- stats_init()

清楚運行時被收集的統計結構。

- sys_init()

沒有多大用處,因為我們在lwipopts.h中設置NO_SYS 1

Not of much use since we set the NO_SYS 1 option in lwipopts.h, to be called for easy

configuration changes.

 

- mem_init()

通過定義MEM_SIZE初始化動態存儲堆

 

- memp_init()

通過定義MEMP_NUM_x初始化內存池。

 

- pbuf_init()

通過定義PBUF_POOL_SIZE初始化pbuf內存池。

 

- etharp_init()

初始化ARP表和隊列。

注:在這個初始化之后你必須每隔 ARP_TMR_INTERVAL(5)個周期間隔調用etharp_tmr 函數。

 

- ip_init()

不常用,處理將要放生的改變時被調用。

 

- udp_init()

清除UDP PCB列表。

- tcp_init()

清除TCP PCB列表并清除一些內部定時器。

注:在這個初始化函數之后,你必須按預先確定的每個周期內調用tcp_fasttmr()  tcp_slowtmr()函數。

 

- netif_add(struct netif *netif, struct ip_addr *ipaddr,

struct ip_addr *netmask, struct ip_addr *gw,

void *state, err_t (* init)(struct netif *netif),

err_t (* input)(struct pbuf *p, struct netif *netif))

netif_list列表中增加你的網絡接口。分配一個netif結構體并傳遞一個指向這個結構體的指針作為第一個參數。當使用DHCP時給定的ip_addr結構體會被清除,或者用其它數據填充它們。"state"指針可能為NULL

函數指針"init"必須指向你的以太網netif接口初始化函數,下面舉例說用該函數的應用。

err_t netif_if_init(struct netif *netif)

{

u8_t i;

for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i];

init_my_eth_device();

return ERR_OK;

}

為使用以太網驅動器(For ethernet drivers),函數指針"input"必須指向"netif/etharp.h"中聲明的ethernet_input() 函數。其它驅動器(Other drivers)必須使用"lwip/ip.h"中聲明的ip_input()函數。

 

- netif_set_default(struct netif *netif)

注冊默認網絡接口

 

- netif_set_up(struct netif *netif)

netif完全配置后,這個函數必須被調用。

 

- dhcp_start(struct netif *netif)

在第一次調用時為這個接口創建一個新的DHCP客戶端。

注:啟動這個客戶端后你必須按照預先設定的間隔周期性的調用dhcp_fine_tmr() dhcp_coarse_tmr()函數。

       你可以通過結構體netif->dhcp查看真實的DHCP狀態。

 

 

--- 優化提示

       首先要做的是優化src/core/inet.c中的lwip_standard_checksum()程序。你可以使用

#define LWIP_CHKSUM  <your_checksum_routine>

來重寫這個標準函數。

inet.c中使用C語言編寫的例子,你也可以使用匯編語言編寫。

RFC1071是這個主題的很好的介紹。

如果你使用小端處理器,另一個有效的改善是用匯編語言或者內聯函數代替htons()  htonl()函數。

#define LWIP_PLATFORM_BYTESWAP 1

#define LWIP_PLATFORM_HTONS(x)  <your_htons>

#define LWIP_PLATFORM_HTONL(x)  <your_htonl>

       如果你的網絡讀到的速度比最大線速還要大,檢查你的網絡接口。如果硬件不能提供良好的服務,會經常快速的發生緩沖區溢出現象。舉例來說,當使用cs8900處理器時,調用cs8900if_service(ethif)函數可能很頻繁出現上述現象。當使用的RTOS允許cs8900使用中斷喚醒一個服務于一個你的使用一個二進制信號量或事件標志的驅動程序的高優先級任務。

       當產品發布時,建議設置LWIP_STATS0



實際當中,太多的函數會造成難以維護,所以會適量精簡。

回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 高清色 | 久久黄网 | 91免费观看国产 | 好姑娘高清在线观看电影 | 婷婷国产一区二区三区 | 国产区免费视频 | 欧美一区二区三区的 | 99精品一区二区 | 91精品国产一区二区三区动漫 | 色性av | 欧美在线a | 久久国产精品一区二区三区 | 四虎在线播放 | 国内av在线 | 国产精品国产成人国产三级 | 手机av在线 | 国产精品久久影院 | 韩国av电影网| 欧美性猛交一区二区三区精品 | 三级黄片毛片 | 最新中文字幕第一页视频 | 特级丰满少妇一级aaaa爱毛片 | 久久久成人网 | 中文字幕免费 | 天天干天天插天天 | 福利影院在线看 | 青青草一区 | 国产欧美日韩在线 | 精品欧美一区二区精品久久久 | 日韩三区在线观看 | jdav视频在线观看免费 | 日韩欧美高清 | 欧美亚洲高清 | 国产视频一视频二 | 欧美精品一区二区三区在线 | 久久精品一区二区三区四区 | 黄色网一级片 | 国产欧美日韩一区 | 国产精品一区二区欧美黑人喷潮水 | 精品国产乱码久久久久久图片 | 亚洲一区二区在线视频 |