• 17-ESP8266 SDK开发基础入门篇--TCP服务器 RTOS版,小试牛刀


    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
    ",(uint8_t)(ipaddr.addr),(uint8_t)(ipaddr.addr >> 8),(uint8_t)(ipaddr.addr >> 16),(uint8_t)(ipaddr.addr >> 24));
                printf("Port:%d
    ",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
    ",(uint8_t)(ipaddr.addr),(uint8_t)(ipaddr.addr >> 8),(uint8_t)(ipaddr.addr >> 16),(uint8_t)(ipaddr.addr >> 24));
                printf("Port:%d
    ",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

  • 相关阅读:
    Hsqldb中设置主键,并让主键自增
    解决Hsqldb指针只能单向移动,不能回滚问题(.first())
    MySql服务的启动和停止
    jetty和tomcat比较
    查看某一端口被什么程序占用
    小程序修改swiper小圆点
    小程序返回上一页。或者某一页上刷新返回页
    小程序或者vue商品秒杀倒计时
    小程序 wx.switchTab 不能带参数的解决办法
    微信小程序倒计时60S
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/11112015.html
Copyright © 2020-2023  润新知