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