- #include "tcpserve.h"
- //TCP Server接收数据缓冲区
- uint8_t tcp_server_recvbuf[TCP_SERVER_RX_BUFSIZE];
- uint8_t tcp_server_sendbuf[TCP_CLIENT_TX_BUFSIZE];
- struct ip4_addr rmtipaddr_serve;
- uint16_t recv_len_serve;
- uint16_t send_len_serve;
- uint8_t SIP_ADDRESS[4];
- struct tcp_pcb *tpcb;
- //TCP服务器发送数据内容
- //const u8 *tcp_server_sendbuf="Explorer STM32F407 TCP Server send data\r\n";
- //TCP Server 测试全局状态标记变量
- //bit7:0,没有数据要发送;1,有数据要发送
- //bit6:0,没有收到数据;1,收到数据了.
- //bit5:0,没有客户端连接上;1,有客户端连接上了.
- //bit4~0:保留
- uint8_t tcp_server_flag;
- void tcp_server_init(void)
- {
- int remote_ip[4];
-
- recv_len_serve = 0;
- send_len_serve = 0;
-
- tcp_server_flag = 0;
-
-
- }
- void tcp_server_handle(void)
- {
- static uint16_t retry = 0;
- err_t err;
- struct tcp_pcb *tcppcbconn; //定义一个TCP服务器控制块
-
- if (tpcb == NULL) {
- tpcb= tcp_new(); //创建一个新的pcb
- if (tpcb) { //创建成功
- //ip_get_option(tpcb, SOF_KEEPALIVE); //保持激活状态
- err = tcp_bind(tpcb,IP_ADDR_ANY,TCP_SERVER_PORT); //连接到目的地址的指定端口上,当连接成功后回调tcp_client_connected()函数
- if(err==ERR_OK) //绑定完成
- {
-
- tcppcbconn=tcp_listen(tpcb); //设置tcppcb进入监听状态
- tcp_accept(tpcb,tcp_server_accept); //初始化LWIP的tcp_accept的回调函数
-
- }
- //printf("tcp connect...\r\n");
- }
- }
- if (tpcb) {
- if (++retry > MAX_RETRY_NUM) {
- if ((tcp_server_flag & 1<<5) == 0) { //未连接上,则尝试重连
- //printf("retry again\r\n");
- tcp_server_connection_close(tpcb, 0); //关闭连接
- tpcb = tcp_new(); //创建一个新的pcb
- if (tpcb) { //创建成功
- //ip_get_option(tpcb, SOF_KEEPALIVE);
- err = tcp_bind(tpcb,IP_ADDR_ANY,TCP_SERVER_PORT); //连接到目的地址的指定端口上,当连接成功后回调tcp_client_connected()函数
- if(err==ERR_OK) //绑定完成
- {
-
- tcppcbconn=tcp_listen(tpcb); //设置tcppcb进入监听状态
- tcp_accept(tpcb,tcp_server_accept); //初始化LWIP的tcp_accept的回调函数
- }
- }
- }
- retry = 0;
- }
- HAL_Delay(10);
- }
- }
- //lwIP tcp_accept()的回调函数
- err_t tcp_server_accept(void *arg,struct tcp_pcb *newpcb,err_t err)
- {
- err_t ret_err;
- struct tcp_server_struct *es;
- LWIP_UNUSED_ARG(arg);
- LWIP_UNUSED_ARG(err);
- tcp_setprio(newpcb,TCP_PRIO_MIN);//设置新创建的pcb优先级
- es=(struct tcp_server_struct*)mem_malloc(sizeof(struct tcp_server_struct)); //分配内存
- if(es!=NULL) //内存分配成功
- {
- es->state=ES_TCPSERVER_ACCEPTED; //接收连接
- es->pcb=newpcb;
- es->p=NULL;
-
- tcp_arg(newpcb,es);
- tcp_recv(newpcb,tcp_server_recv); //初始化tcp_recv()的回调函数
- tcp_err(newpcb,tcp_server_error); //初始化tcp_err()回调函数
- tcp_poll(newpcb,tcp_server_poll,1); //初始化tcp_poll回调函数
- tcp_sent(newpcb,tcp_server_sent); //初始化发送回调函数
-
- tcp_server_flag|=1<<5; //标记有客户端连上了
- SIP_ADDRESS[0]=newpcb->remote_ip.addr&0xff; //IADDR4
- SIP_ADDRESS[1]=(newpcb->remote_ip.addr>>8)&0xff; //IADDR3
- SIP_ADDRESS[2]=(newpcb->remote_ip.addr>>16)&0xff; //IADDR2
- SIP_ADDRESS[3]=(newpcb->remote_ip.addr>>24)&0xff; //IADDR1
- ret_err=ERR_OK;
- }else ret_err=ERR_MEM;
- return ret_err;
- }
- //lwIP tcp_recv()函数的回调函数
- err_t tcp_server_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
- {
- err_t ret_err;
- uint32_t data_len = 0;
- struct pbuf *q;
- struct tcp_server_struct *es;
- LWIP_ASSERT("arg != NULL",arg != NULL);
- es=(struct tcp_server_struct *)arg;
- if(p==NULL) //从客户端接收到空数据
- {
- es->state=ES_TCPSERVER_CLOSING;//需要关闭TCP 连接了
- es->p=p;
- ret_err=ERR_OK;
- }else if(err!=ERR_OK) //从客户端接收到一个非空数据,但是由于某种原因err!=ERR_OK
- {
- if(p)pbuf_free(p); //释放接收pbuf
- ret_err=err;
- }else if(es->state==ES_TCPSERVER_ACCEPTED) //处于连接状态
- {
- if(p!=NULL) //当处于连接状态并且接收到的数据不为空时将其打印出来
- {
- memset(tcp_server_recvbuf,0,TCP_SERVER_RX_BUFSIZE); //数据接收缓冲区清零
- for(q=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客户端接收数组,跳出
- }
- tcp_server_flag|=1<<6; //标记接收到数据了
- SIP_ADDRESS[0]=tpcb->remote_ip.addr&0xff; //IADDR4
- SIP_ADDRESS[1]=(tpcb->remote_ip.addr>>8)&0xff; //IADDR3
- SIP_ADDRESS[2]=(tpcb->remote_ip.addr>>16)&0xff;//IADDR2
- SIP_ADDRESS[3]=(tpcb->remote_ip.addr>>24)&0xff;//IADDR1
- tcp_recved(tpcb,p->tot_len);//用于获取接收数据,通知LWIP可以获取更多数据
- pbuf_free(p); //释放内存
- ret_err=ERR_OK;
- }
- }else//服务器关闭了
- {
- tcp_recved(tpcb,p->tot_len);//用于获取接收数据,通知LWIP可以获取更多数据
- es->p=NULL;
- pbuf_free(p); //释放内存
- ret_err=ERR_OK;
- }
- return ret_err;
- }
- //lwIP tcp_err函数的回调函数
- void tcp_server_error(void *arg,err_t err)
- {
- LWIP_UNUSED_ARG(err);
- //printf("tcp error:%x\r\n",(uint32_t)arg);
- if(arg!=NULL)mem_free(arg);//释放内存
- }
- //lwIP tcp_poll的回调函数
- err_t tcp_server_poll(void *arg, struct tcp_pcb *tpcb)
- {
- err_t ret_err;
- struct tcp_server_struct *es;
- es=(struct tcp_server_struct *)arg;
- if(es!=NULL)
- {
- if(tcp_server_flag&(1<<7)) //判断是否有数据要发送
- {
- es->p=pbuf_alloc(PBUF_TRANSPORT,send_len_serve ,PBUF_POOL);//申请内存
- pbuf_take(es->p,(char*)tcp_server_sendbuf,send_len_serve);
- tcp_server_senddata(tpcb,es); //轮询的时候发送要发送的数据
- tcp_server_flag&=~(1<<7); //清除数据发送标志位
- if(es->p!=NULL)pbuf_free(es->p); //释放内存
- }else if(es->state==ES_TCPSERVER_CLOSING)//需要关闭连接?执行关闭操作
- {
- tcp_server_connection_close(tpcb,es);//关闭连接
- }
- ret_err=ERR_OK;
- }else
- {
- tcp_abort(tpcb);//终止连接,删除pcb控制块
- ret_err=ERR_ABRT;
- }
- return ret_err;
- }
- //lwIP tcp_sent的回调函数(当从远端主机接收到ACK信号后发送数据)
- err_t tcp_server_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
- {
- struct tcp_server_struct *es;
- LWIP_UNUSED_ARG(len);
- es = (struct tcp_server_struct *) arg;
- if(es->p)tcp_server_senddata(tpcb,es);//发送数据
- return ERR_OK;
- }
- //此函数用来发送数据
- void tcp_server_senddata(struct tcp_pcb *tpcb, struct tcp_server_struct *es)
- {
- struct pbuf *ptr;
- uint16_t plen;
- err_t wr_err=ERR_OK;
- while((wr_err==ERR_OK)&&es->p&&(es->p->len<=tcp_sndbuf(tpcb)))
- {
- ptr=es->p;
- wr_err=tcp_write(tpcb,ptr->payload,ptr->len,1);
- if(wr_err==ERR_OK)
- {
- plen=ptr->len;
- es->p=ptr->next; //指向下一个pbuf
- if(es->p)pbuf_ref(es->p); //pbuf的ref加一
- pbuf_free(ptr);
- tcp_recved(tpcb,plen); //更新tcp窗口大小
- }else if(wr_err==ERR_MEM)es->p=ptr;
- }
- }
- //关闭tcp连接
- void tcp_server_connection_close(struct tcp_pcb *tpcb, struct tcp_server_struct *es)
- {
- tcp_close(tpcb);
- tcp_arg(tpcb,NULL);
- tcp_sent(tpcb,NULL);
- tcp_recv(tpcb,NULL);
- tcp_err(tpcb,NULL);
- tcp_poll(tpcb,NULL,0);
- if(es)mem_free(es);
- tcp_server_flag&=~(1<<5);//标记连接断开了
- }
- uint32_t TCPTimer=0; //TCP查询计时器
- uint32_t ARPTimer=0; //ARP查询计时器
- uint32_t lwip_localtime; //lwip本地时间计数器,单位:ms
- #define TCP_TMR_INTERVAL 250
- #define ARP_TMR_INTERVAL 5000
- //LWIP轮询任务
- void lwip_periodic_handle()
- {
- #if LWIP_TCP
- //每250ms调用一次tcp_tmr()函数
- if (lwip_localtime - TCPTimer >= TCP_TMR_INTERVAL)
- {
- TCPTimer = lwip_localtime;
- tcp_tmr();
- }
- #endif
- //ARP每5s周期性调用一次
- if ((lwip_localtime - ARPTimer) >= ARP_TMR_INTERVAL)
- {
- ARPTimer = lwip_localtime;
- etharp_tmr();
- }
- #if LWIP_DHCP //如果使用DHCP的话
- //每500ms调用一次dhcp_fine_tmr()
- if (lwip_localtime - DHCPfineTimer >= DHCP_FINE_TIMER_MSECS)
- {
- DHCPfineTimer = lwip_localtime;
- dhcp_fine_tmr();
- if ((lwipdev.dhcpstatus != 2)&&(lwipdev.dhcpstatus != 0XFF))
- {
- lwip_dhcp_process_handle(); //DHCP处理
- }
- }
- //每60s执行一次DHCP粗糙处理
- if (lwip_localtime - DHCPcoarseTimer >= DHCP_COARSE_TIMER_MSECS)
- {
- DHCPcoarseTimer = lwip_localtime;
- dhcp_coarse_tmr();
- }
- #endif
- }
- extern void tcp_pcb_purge(struct tcp_pcb *pcb); //在 tcp.c里面
- extern struct tcp_pcb *tcp_active_pcbs; //在 tcp.c里面
- extern struct tcp_pcb *tcp_tw_pcbs; //在 tcp.c里面
- //强制删除TCP Server主动断开时的time wait
- void tcp_server_remove_timewait(void)
- {
- struct tcp_pcb *pcb,*pcb2;
- uint8_t t=0;
- while(tcp_active_pcbs!=NULL&&t<200)
- {
- lwip_periodic_handle(); //继续轮询
-
- t++;
- //等待tcp_active_pcbs为空
- HAL_Delay(10);
- }
- pcb=tcp_tw_pcbs;
- while(pcb!=NULL)//如果有等待状态的pcbs
- {
- tcp_pcb_purge(pcb);
- tcp_tw_pcbs=pcb->next;
- pcb2=pcb;
- pcb=pcb->next;
- memp_free(MEMP_TCP_PCB,pcb2);
- }
- }
- uint16_t tcp_server_recv_data(uint8_t* data, uint16_t size)
- {
- uint16_t ret = 0;
- if (tcp_server_flag & 1<<6) { //收到数据
- memcpy(data, tcp_server_recvbuf, recv_len_serve);//void *memcpy(void *destin, void *source, unsigned n);destin-- 指向用于存储复制内容的目标数组,类型强制转换为 void* 指针。source-- 指向要复制的数据源,类型强制转换为 void* 指针。n-- 要被复制的字节数。
- ret = recv_len_serve;
- tcp_server_flag &= ~(1<<6); //标记数据已经被处理了.
- }
-
- return ret;
- }
- void tcp_server_send_data(const uint8_t* data, uint16_t size)
- {
- if (tpcb) {
- tcp_write(tpcb, data, size, 1);//构造一个报文并放到控制块的发送缓冲队列中
- tcp_output(tpcb);//将发送缓冲队列中的数据发送出去
- }
- }