17-ESP8266 SDK開發基礎入門篇--TCP服務器 RTOS版,小試牛刀

http://www.javashuo.com/article/p-qjlgczuc-cs.htmlhtml

 

如今開始寫...數組

lwip便可以用socket 的API  也能夠用 netconn  的API實現網絡通訊緩存

socket  自己其實就是在netconn 上的再一次封裝,因此使用起來更快捷(好多東西又封裝了一下),可是因爲我之前作的項目都是用的netconn ,因此咱仍是用 netconn  實現服務器

畢竟用的更底層,更穩定,更省資源網絡

提到lwip 不得不提一我的   "老衲五木"  你們能夠百度 老衲五木LWIP 我當時學習的時候就是看的他的文章,記得幾年前我在寫一篇文章的時候還吐槽了下socket

這個大神呢 ,他寫文章的時候會扯一扯別的,我也文章的時候也是這樣,也不知道爲何,寫的很入神了以後遍會油然而生一些感慨.函數

這位大神的文章我給你們準備好了學習

 

 

如今能夠不用去看,,先跟着我學會使用,使用着使用着,若是遇到問題了,那麼咱再看文檔去解決問題測試

首先說一下哈,,其實老衲五木給了一個例子,TCP服務器的例子ui

 

 咱就仍是按照先前說的,先學會用,用着用着哪裏出現問題了再去看文檔

 

 

 

 好如今建個任務,,上一篇是用裸機跑的,此次咱用操做系統跑

 

 

 

 

 

 

 而後我就不一個一個的這樣寫了,,我就一段一段的寫

 

 

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);
}
 

 



主要的就兩個地方須要說一下

 

能夠看這個  http://www.javashuo.com/article/p-xuhlweji-r.html還有一個地方

 

 

 

填的是NETCONN_COPY時, 數據將被先複製到內存緩衝區,而後再發送,這樣會耽誤點時間,還須要開闢內存...可是好處是,

執行完之後就能夠隨意修改 TcpRead (假設這個是咱發送數據用的哈)  裏面的值了.

 

NETCONN_NOCOPY,發送數據的時候是直接從咱原始數組裏面取,而後發送

其它的本身研究哈..測試測試...

 

好如今測試,下載好WIFI程序哈

     

 

 

 好了,先消化消化哈...下節再加上串口的數據轉發給TCP

說一下哈,不管用的哪一種的編譯器或者用的哪一個版本,底層應用該怎麼用仍是怎麼用,就像這個lwip,,由於這些都是徹底徹底通用的...

一句話歸納:就是這麼用.

有個地方說錯了

 

 

err = netconn_recv(newconn,&recvbuf);   這是判斷接沒接收到數據的函數,若是沒有接收到數據就不會往下執行

直至接收到數據才往下執行

能夠分開看

 

 可是並非阻塞哈,別的任務照樣運行,其實我感受是內部每隔10ms檢測有沒有數據過來,沒有的話就return

 

 

http://www.javashuo.com/article/p-gbbgtcpm-e.html

相關文章
相關標籤/搜索