#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);//将发送缓冲队列中的数据发送出去
}
}