前面说了TCP客户端通信,这一篇来讲说单片机做为服务器的通信方法api
tcp客户端和服务器的连接作大的不一样在于服务器是不须要主动连接谁的,他只须要绑定在本身得一个特定的端口之上,等别人来链接就行了,先建立任务数组
//建立TCP服务器线程 //返回值:0 TCP服务器建立成功 // 其余 TCP服务器建立失败 INT8U tcp_server_init(void) { INT8U res; OS_CPU_SR cpu_sr; OS_ENTER_CRITICAL(); //关中断 res = OSTaskCreate(tcp_server_thread,(void*)0,(OS_STK*)&TCPSERVER_TASK_STK[TCPSERVER_STK_SIZE-1],TCPSERVER_PRIO); //建立TCP服务器线程 OS_EXIT_CRITICAL(); //开中断 return res; }
任务循环以下服务器
//tcp服务器任务 static void tcp_server_thread(void *arg) { OS_CPU_SR cpu_sr; u32 data_len = 0; struct pbuf *q; err_t err,recv_err; u8 remot_addr[4]; struct netconn *conn, *newconn; static ip_addr_t ipaddr; static u16_t port; struct netbuf *recvbuf; while(dhcpstatus != 2)//等待dhcp成功 { OSTimeDly(10); //printf("wait dhcp\r\n"); } LWIP_UNUSED_ARG(arg); printf("建立一个TCP连接\r\n"); conn = netconn_new(NETCONN_TCP); //建立一个TCP连接 netconn_bind(conn,IP_ADDR_ANY,TCP_SERVER_PORT); //绑定端口 8088号端口 netconn_listen(conn); //进入监听模式 printf("进入监听模式"); //这个地方阻塞以后会形成客户端连不上,报错为the socket is marked as non blocking,后面研究 // conn->recv_timeout = 10; //禁止阻塞线程 等待10ms while (1) { err = netconn_accept(conn,&newconn); //接收链接请求 newconn->recv_timeout = 10; if (err == ERR_OK) //处理新链接的数据 { printf("处理新链接的数据"); netconn_getaddr(newconn,&ipaddr,&port,0); //获取远端IP地址和端口号 remot_addr[3] = (uint8_t)(ipaddr.addr >> 24); remot_addr[2] = (uint8_t)(ipaddr.addr>> 16); remot_addr[1] = (uint8_t)(ipaddr.addr >> 8); remot_addr[0] = (uint8_t)(ipaddr.addr); printf("主机%d.%d.%d.%d链接上服务器,主机端口号为:%d\r\n",\ remot_addr[0], remot_addr[1],remot_addr[2],remot_addr[3],port); while(1) { if(keyValue == KEY_UP) { keyValue = 0; tcp_server_flag = LWIP_SEND_DATA; } if((tcp_server_flag & LWIP_SEND_DATA) == LWIP_SEND_DATA) //有数据要发送 { err = netconn_write(newconn ,tcp_server_sendbuf,strlen((char*)tcp_server_sendbuf),NETCONN_COPY); //发送tcp_server_sendbuf中的数据 if(err != ERR_OK) { printf("发送失败\r\n"); } tcp_server_flag &= ~LWIP_SEND_DATA; } if((recv_err = netconn_recv(newconn,&recvbuf)) == ERR_OK) //接收到数据 { OS_ENTER_CRITICAL(); //关中断 memset(tcp_server_recvbuf,0,TCP_SERVER_RX_BUFSIZE); //数据接收缓冲区清零 for(q=recvbuf->p;q!=NULL;q=q->next) //遍历完整个pbuf链表 { //判断要拷贝到TCP_SERVER_RX_BUFSIZE中的数据是否大于TCP_SERVER_RX_BUFSIZE的剩余空间,若是大于 //的话就只拷贝TCP_SERVER_RX_BUFSIZE中剩余长度的数据,不然的话就拷贝全部的数据 if(q->len > (TCP_SERVER_RX_BUFSIZE-data_len)) memcpy(tcp_server_recvbuf+data_len,q->payload,(TCP_SERVER_RX_BUFSIZE-data_len));//拷贝数据 else memcpy(tcp_server_recvbuf+data_len,q->payload,q->len); data_len += q->len; if(data_len > TCP_SERVER_RX_BUFSIZE) break; //超出TCP客户端接收数组,跳出 } OS_EXIT_CRITICAL(); //开中断 data_len=0; //复制完成后data_len要清零。 printf("%s\r\n",tcp_server_recvbuf); //经过串口发送接收到的数据 netbuf_delete(recvbuf); }else if(recv_err == ERR_CLSD) //关闭链接 { netconn_close(newconn); netconn_delete(newconn); printf("主机:%d.%d.%d.%d断开与服务器的链接\r\n",remot_addr[0], remot_addr[1],remot_addr[2],remot_addr[3]); break; } } OSTimeDly(10); } OSTimeDly(10); } }
这里面用了两个服务器特有的api,以下socket
netconn_bind(conn,IP_ADDR_ANY,TCP_SERVER_PORT); //绑定端口 8088号端口 netconn_listen(conn); //进入监听模式
其实严格来讲,监听以后应该来一个任务生成一个新的任务处理相应的连接,这个demo里面没这个作,按部就班嘛tcp
代码位置以下ui
http://download.csdn.net/detail/dengrengong/8599075