https://www.cnblogs.com/yangfengwu/p/11105466.html
現在開始寫...
lwip即可以用socket 的API 也可以用 netconn 的API實現網絡通信
socket 本身其實就是在netconn 上的再一次封裝,所以使用起來更快捷(好多東西又封裝了一下),但是由於我以前做的項目都是用的netconn ,所以咱還是用 netconn 實現
畢竟用的更底層,更穩定,更省資源
提到lwip 不得不提一個人 "老衲五木" 大家可以百度 老衲五木LWIP 我當時學習的時候就是看的他的文章,記得幾年前我在寫一篇文章的時候還吐槽了下
這個大神呢 ,他寫文章的時候會扯一扯別的,我也文章的時候也是這樣,也不知道為什么,寫的很入神了之后遍會油然而生一些感慨.
這位大神的文章我給大家准備好了
現在可以不用去看,,先跟着我學會使用,使用着使用着,如果遇到問題了,那么咱再看文檔去解決問題
首先說一下哈,,其實老衲五木給了一個例子,TCP服務器的例子
咱就還是按照先前說的,先學會用,用着用着哪里出現問題了再去看文檔
好現在建個任務,,上一篇是用裸機跑的,這次咱用操作系統跑
然后我就不一個一個的這樣寫了,,我就一段一段的寫
void TcpServerThread(void *date) { struct netconn *conn, *newconn;//conn 保存自身TCP服務器的信息 newconn-保存連接客戶端的信息 err_t err;//有客戶端連接以后,會返回這次連接的錯誤信息 static ip_addr_t ipaddr;//存儲客戶端的地址 static u16_t port;//存儲客戶端的端口號 conn = netconn_new(NETCONN_TCP);//創建一個TCP //注意哈,首先要明白你無論創建 TCP服務器或者客戶端,或者UDP,你創建的時候必須設置下TCP服務器或者客戶端,或者UDP的IP地址和端口號. //網絡之間通信嘛,這是必須的,只有你有IP和端口號了,別人才能和你通信 netconn_bind(conn,IP_ADDR_ANY,8888); //設置conn(TCP服務器) 的IP地址是自己網卡上的IP 設置TCP服務器通信的端口號是8888 (無論創建 TCP服務器或者客戶端,或者UDP,都是必須的) netconn_listen(conn); //使用監聽函數,說明是創建TCP服務器,只有作為服務器才是監聽客戶端連接嘛 //設置任務阻塞時間為10ms (注意哈,這個和(注意哈,這個和vTaskDelay(10/portTICK_RATE_MS)類似,但是一定要用這個 //下面的netconn_accept(conn,&newconn);函數是完全阻塞的,,如果你不設置conn->recv_timeout 程序就停止在那里了,除非有客戶端連接 conn->recv_timeout=10;//任務延時10ms while(1) { err = netconn_accept(conn,&newconn);//等待客戶端連接,有客戶機連接,或者超時了就會往下執行 if (err == ERR_OK)//只有客戶機連接了,並且沒有其它錯誤才會進入 { netconn_getaddr(newconn,&ipaddr,&port,0); //得到客戶端的IP地址和端口號 最后一個參數 1獲取本地IP地址,0獲取客戶端IP地址 //打印客戶端的IP地址 printf("ClientIP:%d.%d.%d.%d\n",(uint8_t)(ipaddr.addr),(uint8_t)(ipaddr.addr >> 8),(uint8_t)(ipaddr.addr >> 16),(uint8_t)(ipaddr.addr >> 24)); printf("Port:%d\n",port);//打印客戶端的端口號 netconn_close(newconn);//關閉連接 netconn_delete(newconn);//刪除連接 } else { conn->recv_timeout=10;//任務延時10ms } } vTaskDelete(NULL); }
上面實現的是,WIFI創建了TCP 然后設置TCP的IP是自身的IP地址(默認是192.168.4.1) 端口號是8888
然后調用了監聽,然后(假設沒有客戶端連接哈) netconn_accept(conn,&newconn);//等待客戶端連接,有客戶機連接,或者超時了就會往下執行
從這里等待10ms 然后超時,往下執行
conn->recv_timeout=10;//任務延時10ms 其實也是設置 等待客戶機的那個函數超時時間是10ms
然后就是這樣循環....
然后如果檢測到客戶端連接了,獲取下客戶端的信息,然后打印下,然后關閉連接...然后又是等待連接,然后呢又是任務延時.....循環起來了
現在測試,下載進去WIFI程序
這次安裝這個,這個是我當年寫的APP,用我的這個是因為,下面的那個不能檢測到服務器主動斷開了連接......
我的這個做了這個功能





現在做一個功能,客戶端發過來什么數據,咱就回復什么數據,同時把接收的數據串口輸出



void TcpServerThread(void *date) { struct netconn *conn, *newconn;//conn 保存自身TCP服務器的信息 newconn-保存連接客戶端的信息 err_t err;//有客戶端連接以后,會返回這次連接的錯誤信息 static ip_addr_t ipaddr;//存儲客戶端的地址 static u16_t port;//存儲客戶端的端口號 int i = 0; struct pbuf *q;//用此變量來操作鏈表,可以看一下 https://www.cnblogs.com/yangfengwu/p/5778872.html u32 data_len =0;//獲取接收的數據個數 unsigned char TcpRead[1024]={0};//接收數據緩存的數組,最大接收1024字節 conn = netconn_new(NETCONN_TCP);//創建一個TCP //注意哈,首先要明白你無論創建 TCP服務器或者客戶端,或者UDP,你創建的時候必須設置下TCP服務器或者客戶端,或者UDP的IP地址和端口號. //網絡之間通信嘛,這是必須的,只有你有IP和端口號了,別人才能和你通信 netconn_bind(conn,IP_ADDR_ANY,8888); //設置conn(TCP服務器) 的IP地址是自己網卡上的IP 設置TCP服務器通信的端口號是8888 (無論創建 TCP服務器或者客戶端,或者UDP,都是必須的) netconn_listen(conn); //使用監聽函數,說明是創建TCP服務器,只有作為服務器才是監聽客戶端連接嘛 //設置任務阻塞時間為10ms (注意哈,這個和vTaskDelay(10/portTICK_RATE_MS)類似,但是一定要用這個 //下面的netconn_accept(conn,&newconn);函數是完全阻塞的,,如果你不設置conn->recv_timeout 程序就停止在那里了,除非有客戶端連接 conn->recv_timeout=10;//任務延時10ms while(1) { err = netconn_accept(conn,&newconn);//等待客戶端連接,有客戶機連接,或者超時了就會往下執行 if (err == ERR_OK)//只有客戶機連接了,並且沒有其它錯誤才會進入 { struct netbuf *recvbuf;//創建接收數據的結構體,這是lwip提供的緩存數據用的 netconn_getaddr(newconn,&ipaddr,&port,0); //得到客戶端的IP地址和端口號 最后一個參數 1獲取本地IP地址,0獲取遠程IP地址 //打印客戶端的IP地址 printf("ClientIP:%d.%d.%d.%d\n",(uint8_t)(ipaddr.addr),(uint8_t)(ipaddr.addr >> 8),(uint8_t)(ipaddr.addr >> 16),(uint8_t)(ipaddr.addr >> 24)); printf("Port:%d\n",port);//打印客戶端的端口號 // netconn_close(newconn);//關閉連接 // netconn_delete(newconn);//刪除連接 while(1)//一直在這個里面接收處理數據 { if((err = netconn_recv(newconn,&recvbuf)) == ERR_OK)//接收到客戶端發過來的數據,,這個是阻塞的,,咱上面設置的是10ms超時,,所以每次到這里都會延時10ms(執行別的任務去了) { taskENTER_CRITICAL();//關閉中斷,禁止其它任務打斷,防止讀數據出現錯誤 data_len = 0; for( q = recvbuf->p; q != NULL; q = q->next ) //遍歷完整個pbuf鏈表 { //判斷要拷貝到緩存數組中的數據是否大於緩存數組的剩余空間,如果大於 //的話就只拷貝緩存數組中剩余長度的數據,否則的話就拷貝所有的數據 if( q->len > ( 1024-data_len ) ) memcpy(TcpRead+data_len,q->payload,(1024-data_len));//拷貝數據 else memcpy( TcpRead+data_len, q->payload, q->len ); data_len += q->len; if(data_len > 1024)//超出TCP客戶端接收數組,跳出 break; } taskEXIT_CRITICAL();//打開中斷 //newconn--發給這個客戶端,發送的數組,發送的個數,最后有好幾個取值,具體看文章(太多寫不開) err = netconn_write(newconn ,TcpRead,data_len ,NETCONN_NOCOPY);//發送數據 for(i=0;i<data_len;i++) { USART_SendData(UART0, TcpRead[i]);//接收的數據發給串口 } } } } else { conn->recv_timeout=10;//任務延時10ms } } vTaskDelete(NULL); }
主要的就兩個地方需要說一下

可以看這個 https://www.cnblogs.com/yangfengwu/p/5778872.html
還有一個地方


填的是NETCONN_COPY時, 數據將被先復制到內存緩沖區,然后再發送,這樣會耽誤點時間,還需要開辟內存...但是好處是,
執行完以后就可以隨意修改 TcpRead (假設這個是咱發送數據用的哈) 里面的值了.
NETCONN_NOCOPY,發送數據的時候是直接從咱原始數組里面取,然后發送
其它的自己研究哈..測試測試...
好現在測試,下載好WIFI程序哈
好了,先消化消化哈...下節再加上串口的數據轉發給TCP
說一下哈,無論用的哪種的編譯器或者用的哪個版本,底層應用該怎么用還是怎么用,就像這個lwip,,因為這些都是完全完全通用的...
一句話概括:就是這么用.
有個地方說錯了
err = netconn_recv(newconn,&recvbuf); 這是判斷接沒接收到數據的函數,如果沒有接收到數據就不會往下執行
直至接收到數據才往下執行
可以分開看
但是並不是阻塞哈,別的任務照樣運行,其實我感覺是內部每隔10ms檢測有沒有數據過來,沒有的話就return
https://www.cnblogs.com/yangfengwu/p/11130428.html