一、LWIP 中 中 RAW API ?編程接口中與 TCP ?相關的函數
二、LWIP TCP RAW API 函數
三、LwIP_Periodic_Handle函數
LwIP_Periodic_Handle 函數是一個必須被無限循環調用的 LwIP支持函數,一般在 main函數的無限循環中調用,主要功能是為 LwIP各個模塊提供時間并查詢鏈路狀態,該 函數有一個形參,用于指示當前時間,單位為 ms。 對于 TCP功能,每 250ms執行一次 tcp_tmr函數;對于 ARP,每 5s 執 行一次 etharp_tmr函數;對于鏈路狀態檢測,每 1s 執行一次ETH_CheckLinkStatus 函數; 對于 DHCP功能,每 500ms執行一次 dhcp_fine_tmr函數,如果 DHCP處于DHCP_START 或 DHCP_WAIT_ADDRESS 狀態就執行LwIP_DHCP_Process_Handle 函數,對于 DHCP功 能,還有每 60s 執行一次 dhcp_coarse_tmr函數。
四、TCP客戶端連接代碼
tcpclinet.c
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"
#include <stdio.h>
#include <string.h>
#include "main.h"static void client_err(void *arg, err_t err) //出現錯誤時調用這個函數,打印錯誤信息,并嘗試重新連接
{printf("連接錯誤!!\n");printf("嘗試重連!!\n");printf("重新初始化客戶端\n");TCP_Client_Init();
}static err_t client_send(void *arg, struct tcp_pcb *tpcb) //發送函數,調用了tcp_write函數
{uint8_t send_buf[]= "我是客戶端,是你的好哥哥\n";//發送數據到服務器tcp_write(tpcb, send_buf, sizeof(send_buf), 1); return ERR_OK;
}static err_t client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{if (p != NULL) { /* 接收數據*/tcp_recved(tpcb, p->tot_len);/* 返回接收到的數據*/ tcp_write(tpcb, p->payload, p->tot_len, 1);memset(p->payload, 0 , p->tot_len);pbuf_free(p);} else if (err == ERR_OK) {//服務器斷開連接printf("服務器斷開連接!\n");tcp_close(tpcb);//重新連接TCP_Client_Init();}return ERR_OK;
}static err_t client_connected(void *arg, struct tcp_pcb *pcb, err_t err)
{printf("connected ok!\n");//注冊一個周期性回調函數tcp_poll(pcb,client_send,2);//注冊一個接收函數tcp_recv(pcb,client_recv);return ERR_OK;
}void TCP_Client_Init(void)
{ struct tcp_pcb *client_pcb = NULL; //這一句一定要放在里面,否則會沒用ip4_addr_t server_ip; //因為客戶端要主動去連接服務器,所以要知道服務器的IP地址/* 創建一個TCP控制塊 */client_pcb = tcp_new(); IP4_ADDR(&server_ip, DEST_IP_ADDR0,DEST_IP_ADDR1,DEST_IP_ADDR2,DEST_IP_ADDR3);//合并IP地址printf("客戶端開始連接!\n");//開始連接tcp_connect(client_pcb, &server_ip, TCP_CLIENT_PORT, client_connected);ip_set_option(client_pcb, SOF_KEEPALIVE); printf("已經調用了tcp_connect函數\n");//注冊異常處理tcp_err(client_pcb, client_err);printf("已經注冊異常處理函數\n");
}
tcpclinet.h?
#ifndef _TCPCLIENT_H_
#define _TCPCLIENT_H_#define TCP_CLIENT_PORT 5001void TCP_Client_Init(void);#endif
五、TCP服務器連接代碼
tcpserver.c
#include "tcpserver.h"
#include "lwip/netif.h"
#include "lwip/ip.h"
#include "lwip/tcp.h"
#include "lwip/init.h"
#include "netif/etharp.h"
#include "lwip/udp.h"
#include "lwip/pbuf.h"
#include <stdio.h>
#include <string.h>static err_t tcpecho_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{ //對應接收數據連接的控制塊 接收到的數據 if (p != NULL) { //int a = 666;/* 更新窗口*/tcp_recved(tpcb, p->tot_len); //讀取數據的控制塊 得到所有數據的長度 /* 返回接收到的數據*/ //tcp_write(tpcb, p->payload, p->tot_len, 1);uint8_t send_buf1[]= "我收到了你的信息!是";uint8_t send_buf2[]= "嗎?\n"; tcp_write(tpcb, send_buf1, sizeof(send_buf1), 1);tcp_write(tpcb, p->payload, p->tot_len, 1); tcp_write(tpcb, send_buf2, sizeof(send_buf2), 1); memset(p->payload, 0 , p->tot_len);pbuf_free(p);} else if (err == ERR_OK) //檢測到對方主動關閉連接時,也會調用recv函數,此時p為空{return tcp_close(tpcb);}return ERR_OK;
}static err_t tcpecho_accept(void *arg, struct tcp_pcb *newpcb, err_t err) //由于這個函數是*tcp_accept_fn類型的//形參的數量和類型必須一致
{ tcp_recv(newpcb, tcpecho_recv); //當收到數據時,回調用戶自己寫的tcpecho_recvreturn ERR_OK;
}void TCP_Echo_Init(void)
{struct tcp_pcb *server_pcb = NULL; /* 創建一個TCP控制塊 */server_pcb = tcp_new(); printf("創建了一個控制塊\n");/* 綁定TCP控制塊 */tcp_bind(server_pcb, IP_ADDR_ANY, TCP_ECHO_PORT); printf("已經綁定一個控制塊\n");/* 進入監聽狀態 */server_pcb = tcp_listen(server_pcb);printf("進入監聽狀態\n"); /* 處理連接 注冊函數,偵聽到連接時被注冊的函數被回調 */ tcp_accept(server_pcb, tcpecho_accept); //偵聽到連接后,回調用戶編寫的tcpecho_accept //這個函數是*tcp_accept_fn類型的
}
tcpserver.h
#ifndef _TCPECHO_H_
#define _TCPECHO_H_#define TCP_ECHO_PORT 5001void TCP_Echo_Init(void);#endif