有关于TCP协议的知识在上一章已经有过描述,这里我们直接使用API来实现TCP服务器模式。
#include "tcp_server.h"
#include "delay.h"
#include "usart1.h"
#include "lcd.h"
#include "malloc.h"
#include "string.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
#include "lwip/memp.h"
#include "lwip/mem.h"
#include "comm.h"
//TCP Server 测试全局状态标记变量
//bit7:0,没有数据要发送;1,有数据要发送
//bit6:0,没有收到数据;1,收到数据了.
//bit5:0,没有客户端连接上;1,有客户端连接上了.
//bit4~0:保留
u8 tcp_server_flag;
//关闭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 ) ; //标记连接断开了
}
// tcp_recv函数的回调函数
u8 tcp_server_recvbuf[ TCP_SERVER_RX_BUFSIZE ] ; //TCP Server接收数据缓冲区
err_t tcp_server_recv( void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err )
{
err_t ret_err ;
u32 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 ;
}
//从客户端接收到一个非空数据,但是由于某种原因err!=ERR_OK
else if( 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 ) ; //数据接收缓冲区清零
//遍历完整个pbuf链表
for( q=p; q!=NULL; q=q->next )
{
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 ;
//超出TCP客户端接收数组,跳出
if( data_len>TCP_SERVER_RX_BUFSIZE )
break ;
}
tcp_server_flag |= 1<<6 ; //标记接收到数据了
lwipdev.remoteip[ 0 ] = tpcb->remote_ip.addr&0xFF ; //IADDR4
lwipdev.remoteip[ 1 ] = ( tpcb->remote_ip.addr>>8 )&0xFF ; //IADDR3
lwipdev.remoteip[ 2 ] = ( tpcb->remote_ip.addr>>16 )&0xFF ; //IADDR2
lwipdev.remoteip[ 3 ] = ( tpcb->remote_ip.addr>>24 )&0xFF ; //IADDR1
tcp_recved( tpcb, p->tot_len ) ; //用于获取接收数据
pbuf_free( p ) ; //释放内存
ret_err = ERR_OK ;
}
}
//服务器关闭了
else
{
tcp_recved( tpcb, p->tot_len ); //用于获取接收数据
es->p= NULL ;
pbuf_free( p ) ; //释放内存
ret_err = ERR_OK ;
}
return ret_err ;
}
// tcp_err函数的回调函数
void tcp_server_error( void *arg, err_t err )
{
LWIP_UNUSED_ARG( err ) ;
printf( "tcp error:%x\\r\\n", ( u32 )arg ) ;
//释放内存
if( arg!=NULL )
mem_free( arg ) ;
}
//发送数据
void tcp_server_senddata( struct tcp_pcb *tpcb, struct tcp_server_struct *es )
{
struct pbuf *ptr ;
u16 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
//pbuf的ref加一
if( es->p )
pbuf_ref( es->p ) ;
pbuf_free( ptr ) ;
tcp_recved( tpcb, plen ) ; //更新tcp窗口大小
}
else if( wr_err==ERR_MEM )
es->p = ptr ;
}
}
// tcp_poll的回调函数
const u8 *tcp_server_sendbuf = "STM32F103 TCP Server send data\\r\\n" ; //TCP服务器发送数据内容
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, strlen( ( char* )tcp_server_sendbuf ), PBUF_POOL ) ;
pbuf_take( es->p, ( char* )tcp_server_sendbuf, strlen( ( char* )tcp_server_sendbuf ) ) ;
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 ;
}
// 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 ;
}
//强制删除主动断开时的time wait
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里面
void tcp_server_remove_timewait()
{
struct tcp_pcb *pcb, *pcb2 ;
while( tcp_active_pcbs!=NULL )
{
lwip_periodic_handle() ; //继续轮询
lwip_pkt_handle() ;
delay_ms( 10 ) ; //等待tcp_active_pcbs为空
}
pcb = tcp_tw_pcbs ;
//如果有等待状态的pcbs
while( pcb!=NULL )
{
tcp_pcb_purge( pcb ) ;
tcp_tw_pcbs = pcb->next ;
pcb2 = pcb ;
pcb = pcb->next ;
memp_free( MEMP_TCP_PCB, pcb2 ) ;
}
}
// 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 ; //标记有客户端连上了
lwipdev.remoteip[ 0 ] = newpcb->remote_ip.addr&0xFF ; //IADDR4
lwipdev.remoteip[ 1 ] = ( newpcb->remote_ip.addr>>8 )&0xFF ; //IADDR3
lwipdev.remoteip[ 2 ] = ( newpcb->remote_ip.addr>>16 )&0xFF ; //IADDR2
lwipdev.remoteip[ 3 ] = ( newpcb->remote_ip.addr>>24 )&0xFF ; //IADDR1
ret_err = ERR_OK ;
}
else
ret_err = ERR_MEM ;
return ret_err ;
}
// TCP Server 测试
void tcp_server_test()
{
err_t err ;
struct tcp_pcb *tcppcbnew ; //定义一个TCP服务器控制块
struct tcp_pcb *tcppcbconn ; //定义一个TCP服务器控制块
u8 *tbuf ;
u8 res=0 ;
u8 connflag=0 ; //连接标记
tbuf = mymalloc( SRAMIN, 200 ) ; //申请内存
//内存申请失败了,直接退出
if( tbuf==NULL )
return ;
sprintf( ( char* )tbuf, "Server IP:%d.%d.%d.%d", lwipdev.ip[0], lwipdev.ip[1], lwipdev.ip[2], lwipdev.ip[3] ) ;
LCD_ShowString( 30, 130, tbuf ) ; //服务器IP
sprintf( ( char* )tbuf, "Server Port:%d", TCP_SERVER_PORT ) ;
LCD_ShowString( 30, 150, tbuf ) ; //服务器端口号
tcppcbnew = tcp_new() ; //创建一个新的pcb
//创建成功
if( tcppcbnew )
{
err = tcp_bind( tcppcbnew, IP_ADDR_ANY, TCP_SERVER_PORT ) ; //将本地IP与指定端口号绑定
//绑定完成
if( err==ERR_OK )
{
tcppcbconn = tcp_listen( tcppcbnew ) ; //设置tcppcb进入监听状态
tcp_accept( tcppcbconn, tcp_server_accept ) ; //初始化tcp_accept的回调函数
}
else
res = 1 ;
}
else
res = 1 ;
while( res==0 )
{
//收到数据
if( tcp_server_flag&1<<6 )
{
tcp_server_flag |= 1<<7 ; //标记要发送数据
LCD_ShowString( 30, 210, tcp_server_recvbuf ) ; //显示接收到的数据
tcp_server_flag &= ~( 1<<6 ) ; //标记数据已经被处理了
}
//是否连接上
if( tcp_server_flag&1<<5 )
{
if( connflag==0 )
{
sprintf( ( char* )tbuf, "Client IP:%d.%d.%d.%d", lwipdev.remoteip[0], lwipdev.remoteip[1], lwipdev.remoteip[2], lwipdev.remoteip[3] ) ;
LCD_ShowString( 30, 170, tbuf ) ; //客户端IP
LCD_ShowString( 30, 190, "Receive Data:" ) ; //提示消息
connflag = 1 ; //标记连接了
}
}
else if( connflag )
connflag = 0 ; //标记连接断开了
lwip_periodic_handle() ;
lwip_pkt_handle() ;
delay_ms( 2 ) ;
}
tcp_server_connection_close( tcppcbnew, 0 ) ; //关闭TCP Server连接
tcp_server_connection_close( tcppcbconn, 0 ) ; //关闭TCP Server连接
tcp_server_remove_timewait() ;
memset( tcppcbnew, 0, sizeof( struct tcp_pcb ) ) ;
memset( tcppcbconn, 0, sizeof( struct tcp_pcb ) ) ;
myfree( SRAMIN, tbuf ) ;
}
#ifndef _TCP_SERVER_DEMO_H_
#define _TCP_SERVER_DEMO_H_
#include "sys.h"
#include "lwip/tcp.h"
#include "lwip/pbuf.h"
#define TCP_SERVER_RX_BUFSIZE 2000 //定义tcp server最大接收数据长度
#define TCP_SERVER_PORT 8088 //定义tcp server的端口
//tcp服务器连接状态
enum tcp_server_states
{
ES_TCPSERVER_NONE = 0, //没有连接
ES_TCPSERVER_ACCEPTED, //有客户端连接上了
ES_TCPSERVER_CLOSING, //即将关闭连接
};
//LWIP回调函数使用的结构体
struct tcp_server_struct
{
u8 state; //当前连接状
struct tcp_pcb *pcb; //指向当前的pcb
struct pbuf *p; //指向接收/或传输的pbuf
};
void tcp_server_test( void ) ; //TCP Server测试函数
#endif
#include "sys.h"
#include "delay.h"
#include "usart1.h"
#include "tim.h"
#include "lcd.h"
#include "malloc.h"
#include "dm9000.h"
#include "lwip/netif.h"
#include "comm.h"
#include "lwipopts.h"
#include "tcp_server.h"
int main()
{
u8 buf[ 30 ];
STM32_Clock_Init( 9 ) ; //系统时钟设置
SysTick_Init( 72 ) ; //延时初始化
USART1_Init( 72, 115200 ) ; //串口初始化为115200
LCD_Init() ; //初始化LCD
TIM3_Init( 1000, 719 ) ; //定时器3频率为100hz
my_mem_init( SRAMIN ) ; //初始化内部内存池
while( lwip_comm_init() ) ; //lwip初始化
//等待DHCP获取成功/超时溢出
while( ( lwipdev.dhcpstatus!=2 )&&( lwipdev.dhcpstatus!=0xFF ) )
{
lwip_periodic_handle() ; //LWIP内核需要定时处理的函数
lwip_pkt_handle() ;
}
POINT_COLOR=RED;
LCD_ShowString( 30, 110, "LWIP Init Successed" ) ;
//打印动态IP地址
if( lwipdev.dhcpstatus==2 )
sprintf( ( char* )buf, "DHCP IP:%d.%d.%d.%d", lwipdev.ip[0], lwipdev.ip[1], lwipdev.ip[2], lwipdev.ip[3] ) ;
//打印静态IP地址
else
sprintf( ( char* )buf, "Static IP:%d.%d.%d.%d", lwipdev.ip[0], lwipdev.ip[1], lwipdev.ip[2], lwipdev.ip[3] ) ;
LCD_ShowString( 30, 130, buf ) ;
//得到网速
if( ( DM9000_Get_SpeedAndDuplex()&0x02 )==0x02 )
LCD_ShowString( 30, 150, "Ethernet Speed:10M" ) ;
else
LCD_ShowString( 30, 150, "Ethernet Speed:100M" ) ;
while( 1 )
{
tcp_server_test() ; //TCP服务器测试
lwip_periodic_handle() ;
lwip_pkt_handle() ;
delay_ms( 2 ) ;
}
}
全部0条评论
快来发表一下你的评论吧 !