Hi , 今天还是32的。开源一个基于lwip-raw tcp的框架。
主要也是解决下列这些问题并且减少一些开发者对lwip的研究时间,比如说:
- 盲目使用tcp_connect函数会产生多连接问题
- 若连接的目标不存在(对方无法返回RST)
- 若连接的目标存在且禁止连接时(返回RST)
My_TcpManager.c
/********************************************************************************************************
/ Doon OS-I
/ The Doon-app Wireled manager
/
/
/ (c) Copyright 2019-2023; Micrium, Inc.; ShenZhen, FL
/ All rights reserved. You may obtain a copy of the License at:.
/
/ https://me.youkuaiyun.com/weixin_40952498
/
/ File : My_NetManager.c
/ Version : V0.00.01
/ By : Doon
/ e-mail : 1176964408@qq.com
/ Date : 2019-July 2 Tuesday
/
/ For : STM32F407VET6
/ Mode : Thread mode
/ Toolchain : Source Insight 4.0
********************************************************************************************************/
#include "project.h"
/* <! public function > */
err_t VI_CMode_Callback(void *arg, struct tcp_pcb *newpcb, err_t err);
err_t VI_SMode_Callback(void *arg, struct tcp_pcb *newpcb, err_t err);
err_t VI_CSMode_Recv(void *arg,struct tcp_pcb *tpcb,struct pbuf *p,err_t err);
struct My_NetList * VI_SMode_insert(struct My_NetList *head,struct My_NetList add);
int VI_SMode_deleted(struct My_NetList *head,struct tcp_pcb *socket);
err_t Test_Parse(struct My_NetList *node,char *buffer,unsigned short length);
void VI_CMode_IPParse(const char *name, struct ip_addr *ipaddr, void *arg);
int VI_Net_Suspend(char *name);
int VI_Net_Resume(char *name);
/* pbuf recv parse function */
extern err_t Telnet_Parse(struct My_NetList *node,char *buffer,unsigned short length);
//extern err_t Upper_Parse(struct My_NetList *node,char *buffer,unsigned short length);
//extern err_t Cloud_Parse(struct My_NetList *node,char *buffer,unsigned short length);
//extern err_t Approve_Parse(struct My_NetList *node,char *buffer,unsigned short length);
//extern err_t My_Cloud_Verify( struct My_NetList *node , char *buffer , unsigned short len );
//extern err_t Upper_parse( struct My_NetList *node,char *buffer,unsigned short length );
//extern err_t ReegaBuss_parse( struct My_NetList *node,char *buffer,unsigned short length );
/* connect failed handler */
//extern err_t Cloud_cfhandler(struct My_NetList *node);
/*
* My Net Manager.
*/
My_NetList_Def My_NetList[]=
{
// {
// .name = "Approve", .cs_mode = CS_MODE_CLIENT, .cs_rmport = 10106, .dns = "My-home.com",
// .socket = NULL, .buffer_length = 200, .suspend = false, .Heatbeat_Setting = HEATBEAT_DEFAULT,
// .keepalive = false, .Parse = Approve_Parse, .cf_handler = NULL},
// {
// .name = "Cloud", .cs_mode = CS_MODE_CLIENT, .cs_rmport = 99999, .dns = /*NULL ,*/"47.94.166.7",
// .socket = NULL, .buffer_length = 100, .suspend = false, .Heatbeat_Setting = HEATBEAT_DEFAULT,
// .keepalive = false, .Parse = Cloud_Parse , .cf_handler = NULL/*Cloud_cfhandler*/},
// {
// .name = "Upper", .cs_mode = CS_MODE_SERVER, .cs_loport = 48438, .dns = NULL,
// .socket = NULL , .buffer_length = 2048, .suspend = false , .Heatbeat_Setting = HEATBEAT_DEFAULT,
// .keepalive = false, .Parse = Upper_parse, .cf_handler = NULL},
{
.name = "Telnet", .cs_mode = CS_MODE_SERVER, .cs_loport = 23, .dns = NULL,
.socket = NULL, .buffer_length = 50, .suspend = false , .Heatbeat_Setting = HEATBEAT_NOCOUNT,
.keepalive = true, .Parse = Telnet_Parse, .cf_handler = NULL},
// {
// .name = "ThirdP", .cs_mode = CS_MODE_SERVER, .cs_loport = 48439, .dns = NULL,
// .socket = NULL, .buffer_length = 2048, .suspend = false , .Heatbeat_Setting = HEATBEAT_DEFAULT ,
// .keepalive = false, .Parse = Cloud_Parse, .cf_handler = NULL},
// {
// .name = "Redir", .cs_mode = CS_MODE_CLIENT, .cs_rmport = 9100, .dns = "114.55.171.67",
// .socket = NULL, .buffer_length = 512, .suspend = true , .Heatbeat_Setting = HEATBEAT_DEFAULT,
// .keepalive = false, .Parse = ReegaRes_parse , .cf_handler = NULL},
// {
// .name = "BOSCH", .cs_mode = CS_MODE_CLIENT, .cs_rmport = 0, .dns = NULL,
// .socket = NULL, .buffer_length = 2048, .suspend = true , .Heatbeat_Setting = 140,
// .keepalive = false, .Parse = ReegaBuss_parse , .cf_handler = NULL},
};
static const char * const g_stEthstatus[] = {"CLOSED","LISTEN","SYN_SENT","SYN_RCVD","ESTABLISHED","FIN_WAIT_1","FIN_WAIT_2","CLOSE_WAIT","CLOSING","LAST_ACK","TIME_WAIT"};
/*
* Description : The error of C/S mode
*/
void VI_Neterr(void *arg,err_t err)
{
struct My_NetList *Net_node;
//MyOS_Node_Def item;
if(arg == NULL) return;
else Net_node = (struct My_NetList *)arg;
switch(err)
{
case ERR_ABRT:
/* The package resend 6times. the pcb have free */
/* 1.st set socket to null */
if(Net_node->cs_mode == CS_MODE_CLIENT)
{
/* info the core that some one is break. */
//item.Event_Type = OS_EVENT_NET_CONNECTED;
//item.data.Net_info.cs_mode = Net_node->cs_mode;
//item.data.Net_info.io_select = OS_CONN_CLOSE;
//sprintf(item.data.Net_info.name,"%s",Net_node->name);
//if(Net_node->cs_mode == CS_MODE_CLIENT) item.data.Net_info.port = Net_node->cs_rmport; // client mode
//else item.data.Net_info.port = Net_node->cs_loport; // thirdp mode
//item.data.Net_info.socket = Net_node->socket;
//Enqueue(item);
/* handle the inal touches. */
if(Net_node->connect_state != ESTABLISHED && Net_node->cf_handler != NULL)
{
Net_node->cf_handler(Net_node);
}
Net_node->socket->callback_arg = NULL;
Net_node->socket->recv = NULL;
Net_node->socket->sent = NULL;
Net_node->socket->errf = NULL;
Net_node->socket->poll = NULL;
Net_node->socket->pollinterval = 0;
Net_node->socket = NULL;
Net_node->connect_state = CLOSED;
}
else if(Net_node->cs_mode == CS_MODE_THIRDP)
{
unsigned char length,i;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for(i = 0 ; i < length ; i++)
{
if(Net_node->cs_rmport == My_NetList[i].cs_loport)
{
VI_SMode_deleted(&My_NetList[i],Net_node->socket);
}
}
}
break;
case ERR_RST:
case ERR_CLSD:
/* The package was broken. the pcb have free */
/* 1.st set socket to null */
if(Net_node->cs_mode == CS_MODE_CLIENT)
{
/* info the core that some one is break. */
//item.Event_Type = OS_EVENT_NET_CONNECTED;
//item.data.Net_info.cs_mode = Net_node->cs_mode;
//item.data.Net_info.io_select = OS_CONN_CLOSE;
//sprintf(item.data.Net_info.name,"%s",Net_node->name);
//if(Net_node->cs_mode == CS_MODE_CLIENT) item.data.Net_info.port = Net_node->cs_rmport; // client mode
//else item.data.Net_info.port = Net_node->cs_loport; // thirdp mode
//item.data.Net_info.socket = Net_node->socket;
//Enqueue(item);
/* handle the inal touches. */
if(Net_node->connect_state != ESTABLISHED && Net_node->cf_handler != NULL)
{
Net_node->cf_handler(Net_node);
}
Net_node->socket->callback_arg = NULL;
Net_node->socket->recv = NULL;
Net_node->socket->sent = NULL;
Net_node->socket->errf = NULL;
Net_node->socket->poll = NULL;
Net_node->socket->pollinterval = 0;
Net_node->socket = NULL;
Net_node->connect_state = CLOSED;
}
else if(Net_node->cs_mode == CS_MODE_THIRDP)
{
unsigned char length,i;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for(i = 0 ; i < length ; i++)
{
if(Net_node->cs_rmport == My_NetList[i].cs_loport)
{
VI_SMode_deleted(&My_NetList[i],Net_node->socket);
}
}
}
/* waitting for reconnect or */
break;
default:
Dbg("Unknow err:%d",err);
break;
}
}
/*
*@ The NetManager init .
Server mode : bind , listen and accept socket.
Client mode : connect to remote server.
*/
void VI_NetInit(void)
{
unsigned char i,length;
// err_t err;
// ip_addr_t addr;
// unsigned char l_byTimecount = 0;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
// parse dns's ip first
for(i = 0 ; i < length ; i++)
{
// if(My_NetList[i].cs_mode == CS_MODE_CLIENT)
// {
// if(My_NetList[i].dns != NULL)
// {
// // find it . so we try to parse the ip from dns
// l_byTimecount++;
// err = dns_gethostbyname(My_NetList[i].dns,&addr,VI_CMode_IPParse,&My_NetList[i]);
// if(err == ERR_OK)
// {
// // host name already in octet notation.
// // the callback function will not call
// My_NetList[i].cs_remoteip[3] = addr.addr >> 24; My_NetList[i].cs_remoteip[2] = addr.addr >> 16;
// My_NetList[i].cs_remoteip[1] = addr.addr >> 8; My_NetList[i].cs_remoteip[0] = addr.addr;
// }
// }
// }
// // In the head of init . clear user data
My_NetList[i].connect_state = CLOSED;
memset(My_NetList[i].usrdata.by,0,USR_DATA_LENGTH);
}
// Here we should wait for ETH Interrupt.
// delay_ms(500 * l_byTimecount);
for(i = 0 ; i < length ; i++)
{
switch(My_NetList[i].cs_mode)
{
case CS_MODE_CLIENT:
{
// if(My_NetList[i].suspend == false)
// {
// struct ip_addr rmtipaddr;
// IP4_ADDR(&rmtipaddr,My_NetList[i].cs_remoteip[0],My_NetList[i].cs_remoteip[1],My_NetList[i].cs_remoteip[2],My_NetList[i].cs_remoteip[3]);
// My_NetList[i].socket = tcp_new();
// /* set arg */
// tcp_arg(My_NetList[i].socket,&My_NetList[i]);
// /* set err callback function */
// tcp_err(My_NetList[i].socket,VI_Neterr);
// /* Try to connect */
// tcp_connect(My_NetList[i].socket,&rmtipaddr,My_NetList[i].cs_rmport,VI_CMode_Callback);
// My_NetList[i].connect_state = SYN_SENT;
// }
}break;
case CS_MODE_SERVER:
{
if(My_NetList[i].suspend == false)
{
My_NetList[i].socket = tcp_new();
if(My_NetList[i].socket)
{
tcp_bind(My_NetList[i].socket,IP_ADDR_ANY,My_NetList[i].cs_loport);
My_NetList[i].socket = tcp_listen(My_NetList[i].socket);
tcp_accept(My_NetList[i].socket,VI_SMode_Callback);
tcp_arg(My_NetList[i].socket,&My_NetList[i]);
My_NetList[i].socket->so_options |= (My_NetList[i].keepalive == true ? SOF_KEEPALIVE : 0x00U);
/* fine. each server mode should be a link head */
My_NetList[i].col_next = &My_NetList[i];
My_NetList[i].col_pre = &My_NetList[i];
}
}
}break;
default:
{
Dbg("Unknow cs mode : %d",My_NetList[i].cs_mode);
}break;
}
}
}
/*
*@ The NetManager release .
Server mode : shutdown this socket.
Client mode : susped and disconnect this socket .
*/
void VI_NetRelease(void)
{
unsigned char length,i;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for( i = 0 ; i < length ; i++ )
{
switch(My_NetList[i].cs_mode)
{
case CS_MODE_CLIENT:
{
/* Suspend this socket and disconnect from remote */
// VI_Net_Suspend(My_NetList[i].name);
VI_Net_shutdown(My_NetList[i].name);
}break;
case CS_MODE_SERVER:
{
/* disconnect all socket on this port */
VI_Net_shutdown(My_NetList[i].name);
}break;
default:
Dbg("Unknow cs mode : %d",My_NetList[i].cs_mode);
break;
}
}
}
/*
*@ Description -> check if socket have broken or
*/
void VI_NetReconnectCheck( /*OS_State *MyOS_State*/ void )
{
unsigned char i,length;
struct My_NetList *p = NULL;
//if( MyOS_State->DHCP_Enable == false || ( MyOS_State->DHCP_Enable == true && MyOS_State->Router_State == true ) )
{
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for(i = 0 ; i < length ; i++)
{
/* check which socket should be reconnect */
if(My_NetList[i].connect_state == CLOSED &&\
My_NetList[i].cs_mode == CS_MODE_CLIENT &&\
My_NetList[i].socket == NULL &&\
My_NetList[i].suspend == false)
{
if(My_NetList[i].dns == NULL)
{
struct ip_addr rmtipaddr;
IP4_ADDR(&rmtipaddr,My_NetList[i].cs_remoteip[0],My_NetList[i].cs_remoteip[1],My_NetList[i].cs_remoteip[2],My_NetList[i].cs_remoteip[3]);
/* reconnect do it */
My_NetList[i].socket = tcp_new();
/* set arg */
tcp_arg(My_NetList[i].socket,&My_NetList[i]);
/* set err callback function */
tcp_err(My_NetList[i].socket,VI_Neterr);
/* try to reconnect */
tcp_connect(My_NetList[i].socket,&rmtipaddr,My_NetList[i].cs_rmport,VI_CMode_Callback);
My_NetList[i].connect_state = SYN_SENT;
My_NetList[i].socket->so_options |= (My_NetList[i].keepalive == true ? SOF_KEEPALIVE : 0x00U);
}
else
{
ip_addr_t addr;
struct ip_addr rmtipaddr;
err_t err;
err = dns_gethostbyname(My_NetList[i].dns,&addr,VI_CMode_IPParse,&My_NetList[i]);
if(err == ERR_OK)
{
// host name already in octet notation.
// the callback function will not call
My_NetList[i].cs_remoteip[3] = addr.addr >> 24; My_NetList[i].cs_remoteip[2] = addr.addr >> 16;
My_NetList[i].cs_remoteip[1] = addr.addr >> 8; My_NetList[i].cs_remoteip[0] = addr.addr;
IP4_ADDR(&rmtipaddr,My_NetList[i].cs_remoteip[0],My_NetList[i].cs_remoteip[1],My_NetList[i].cs_remoteip[2],My_NetList[i].cs_remoteip[3]);
/* reconnect do it */
My_NetList[i].socket = tcp_new();
/* set arg */
tcp_arg(My_NetList[i].socket,&My_NetList[i]);
/* set err callback function */
tcp_err(My_NetList[i].socket,VI_Neterr);
/* try to reconnect */
tcp_connect(My_NetList[i].socket,&rmtipaddr,My_NetList[i].cs_rmport,VI_CMode_Callback);
My_NetList[i].connect_state = SYN_SENT;
}
}
}
/* count the heart beat */
switch(My_NetList[i].cs_mode)
{
case CS_MODE_CLIENT:
{
if(My_NetList[i].connect_state == ESTABLISHED)
{
if(My_NetList[i].Heatbeat == 0)
{
/* heart beat time use up */
VI_Net_shutdown(My_NetList[i].name);
}
if(My_NetList[i].Heatbeat != 0xffff) My_NetList[i].Heatbeat--;
}
}break;
case CS_MODE_SERVER:
{
for(p = My_NetList[i].col_next ; p != &My_NetList[i] ; p = p->col_next)
{
if(p->connect_state == ESTABLISHED)
{
if(p->Heatbeat == 0)
{
VI_Net_shutdown(p->name);
}
if(p->Heatbeat != 0xffff) p->Heatbeat--;
}
}
}break;
}
}
}
}
/*
* Get the node
*/
struct My_NetList *VI_Net_Getnode(char *name)
{
unsigned char i,length;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for(i = 0 ; i < length ; i++)
{
if(strcmp(My_NetList[i].name,name) == 0)
{
return &My_NetList[i];
}
}
return NULL;
}
/*
* Suspend this socket
*/
int VI_Net_Suspend(char *name)
{
unsigned char i,length;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for(i = 0 ; i < length ; i++)
{
if(strcmp(My_NetList[i].name,name) == 0)
{
My_NetList[i].suspend = true;
return 0;
}
}
return -1;
}
/*
* Resume this socket
*/
int VI_Net_Resume(char *name)
{
unsigned char i,length;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for(i = 0 ; i < length ; i++)
{
if(strcmp(My_NetList[i].name,name) == 0)
{
My_NetList[i].suspend = false;
return 0;
}
}
return -1;
}
/*
* Heatbeat reset
*/
int VI_Net_HBReset(char *name)
{
unsigned char i,length;
struct My_NetList *p = NULL;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for(i = 0 ; i < length ; i++)
{
switch(My_NetList[i].cs_mode)
{
case CS_MODE_CLIENT:
if(strcmp(My_NetList[i].name,name) == 0)
{
My_NetList[i].Heatbeat = My_NetList[i].Heatbeat_Setting;
return 0;
}
break;
case CS_MODE_SERVER:
for(p = My_NetList[i].col_next ; p != &My_NetList[i] ; p = p->col_next)
{
if(strcmp(p->name,name) == 0)
{
p->Heatbeat = p->Heatbeat_Setting;
return 0;
}
}
break;
default:
break;
}
}
return -1;
}
/*
* shoutdown this socket
*/
int VI_Net_shutdown(char *name)
{
unsigned char i,length;
struct My_NetList *p = NULL;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for(i = 0 ; i < length ; i++)
{
switch(My_NetList[i].cs_mode)
{
case CS_MODE_CLIENT:
{
if(strcmp(My_NetList[i].name,name) == 0)
{
My_NetList[i].socket->callback_arg = NULL;
My_NetList[i].socket->recv = NULL;
My_NetList[i].socket->sent = NULL;
My_NetList[i].socket->errf = NULL;
My_NetList[i].socket->poll = NULL;
My_NetList[i].socket->pollinterval = 0;
tcp_close(My_NetList[i].socket);
My_NetList[i].socket = NULL;
My_NetList[i].connect_state = CLOSED;
return 0;
}
}break;
case CS_MODE_SERVER:
{
if(strcmp(My_NetList[i].name,name) == 0)
{
/* maybe we should close all connection mount this port */
for( p = My_NetList[i].col_next ; p != &My_NetList[i] ; p = p->col_next )
{
p->socket->callback_arg = NULL;
p->socket->recv = NULL;
p->socket->sent = NULL;
p->socket->errf = NULL;
p->socket->poll = NULL;
p->socket->pollinterval = 0;
tcp_close( p->socket );
VI_SMode_deleted( &My_NetList[i] , p->socket );
p->socket = NULL;
}
return 0;
}
else
{
/* find children */
for( p = My_NetList[i].col_next ; p != &My_NetList[i] ; p = p->col_next )
{
if( strcmp( p->name , name ) == 0 )
{
p->socket->callback_arg = NULL;
p->socket->recv = NULL;
p->socket->sent = NULL;
p->socket->errf = NULL;
p->socket->poll = NULL;
p->socket->pollinterval = 0;
tcp_close( p->socket );
VI_SMode_deleted( &My_NetList[i] , p->socket );
p->socket = NULL;
return 0;
}
}
}
}break;
default:
break;
}
}
return -1;
}
/*
* Description : The callback function of client mode
*/
err_t VI_CMode_Callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{
MyOS_Node_Def item;
// The Client mode established
struct My_NetList *Net_node;
Net_node = (struct My_NetList *)arg;
Net_node->connect_state = ESTABLISHED;
Net_node->Heatbeat = Net_node->Heatbeat_Setting;
// Here we should init some callback function
newpcb->recv = VI_CSMode_Recv; // set recv_cb function to a new tcppcb
/* send a info to core */
item.Event_Type = OS_EVENT_NET_CONNECTED;
item.data.Net_info.cs_mode = CS_MODE_CLIENT;
item.data.Net_info.io_select = OS_CONN_CONNECTED;
sprintf(item.data.Net_info.name,"%s",Net_node->name);
item.data.Net_info.port = Net_node->cs_rmport;
item.data.Net_info.socket = newpcb;
Enqueue(item);
return ERR_OK;
}
/*
* Description : The callback function of server mode
*/
err_t VI_SMode_Callback(void *arg, struct tcp_pcb *newpcb, err_t err)
{
// The Server mode established.
struct My_NetList *Net_head;
struct My_NetList Net_node;
//MyOS_Node_Def item;
unsigned char l_byTemp_IP[4];
if(arg != NULL)
{
/* a new connect link to local server */
Net_head = (struct My_NetList *)arg;
l_byTemp_IP[3] = newpcb->remote_ip.addr>>24;
l_byTemp_IP[2] = newpcb->remote_ip.addr>>16;
l_byTemp_IP[1] = newpcb->remote_ip.addr>>8;
l_byTemp_IP[0] = newpcb->remote_ip.addr>>0;
sprintf(Net_node.name,"%d.%d.%d.%d-%d",l_byTemp_IP[0],l_byTemp_IP[1],l_byTemp_IP[2],l_byTemp_IP[3],newpcb->remote_port);
Net_node.cs_mode = CS_MODE_THIRDP;
Net_node.cs_loport = newpcb->remote_port;
Net_node.cs_rmport = Net_head->cs_loport;
Net_node.connect_state = ESTABLISHED;
Net_node.socket = newpcb;
Net_node.socket->recv = VI_CSMode_Recv;
Net_node.socket->errf = VI_Neterr;
Net_node.buffer_length = Net_head->buffer_length;
Net_node.Parse = Net_head->Parse;
Net_node.Heatbeat = Net_head->Heatbeat_Setting;
Net_node.Heatbeat_Setting = Net_head->Heatbeat_Setting;
memset(Net_node.usrdata.by,0,USR_DATA_LENGTH);
/* All init finish. set argument to platform */
Net_node.socket->callback_arg = VI_SMode_insert(Net_head,Net_node);
if(Net_node.socket->callback_arg == NULL)
{
return ERR_MEM;
}
/* send a info to core */
//item.Event_Type = OS_EVENT_NET_CONNECTED;
//item.data.Net_info.cs_mode = CS_MODE_SERVER;
//item.data.Net_info.io_select = OS_CONN_CONNECTED;
//sprintf(item.data.Net_info.name,"%s",Net_node.name);
//item.data.Net_info.port = Net_node.cs_rmport;
//item.data.Net_info.socket = newpcb;
//Enqueue(item);
}
return ERR_OK;
}
/*
* Description : The C/S mode Recv callback function
*/
err_t VI_CSMode_Recv(void *arg,struct tcp_pcb *tpcb,struct pbuf *p,err_t err)
{
struct My_NetList *Net_node;
Net_node = (struct My_NetList *)arg;
struct pbuf *q;
unsigned int data_len = 0;
char *buffer = NULL;
err_t l_unerr;
MyOS_Node_Def item;
if(p == NULL)
{
/* It's a finish info */
/* send a info to core */
item.Event_Type = OS_EVENT_NET_CONNECTED;
item.data.Net_info.cs_mode = Net_node->cs_mode;
item.data.Net_info.io_select = OS_CONN_CLOSE;
sprintf(item.data.Net_info.name,"%s",Net_node->name);
if(Net_node->cs_mode == CS_MODE_CLIENT) item.data.Net_info.port = Net_node->cs_rmport; // client mode
else item.data.Net_info.port = Net_node->cs_loport; // thirdp mode
item.data.Net_info.socket = Net_node->socket;
Enqueue(item);
Net_node->socket->callback_arg = NULL;
Net_node->socket->recv = NULL;
Net_node->socket->sent = NULL;
Net_node->socket->errf = NULL;
Net_node->socket->poll = NULL;
Net_node->socket->pollinterval = 0;
if(Net_node->cs_mode == CS_MODE_THIRDP)
{
unsigned char length,i;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for(i = 0 ; i < length ; i++)
{
if(Net_node->cs_rmport == My_NetList[i].cs_loport)
{
VI_SMode_deleted(&My_NetList[i],Net_node->socket);
tcp_close( tpcb );
return ERR_OK;
}
}
}
Net_node->socket = NULL;
Net_node->connect_state = CLOSED;
tcp_close( tpcb );
}
else
{
buffer = mymalloc(SRAMIN,Net_node->buffer_length);
if(buffer != NULL)
{
memset(buffer,0,Net_node->buffer_length);
for(q = p; q != NULL ; q = q->next)
{
if(q->len > (Net_node->buffer_length - data_len))
{
memcpy(buffer + data_len , q->payload , (Net_node->buffer_length - data_len));
}
else
{
memcpy(buffer + data_len , q->payload , q->len);
}
data_len += q->len;
if(data_len > CLOUD_RECV_BUFF_SIZE)
{
break;
}
}
tcp_recved(tpcb,p->tot_len);
pbuf_free(p);
if(Net_node->Parse != NULL)
{
l_unerr = Net_node->Parse(Net_node,buffer,data_len); // Here we call user parse function
myfree(SRAMIN,buffer);
return l_unerr;
}
myfree(SRAMIN,buffer);
return ERR_OK;
}
else
{
/* maybe memory map is full. add your code here */
return ERR_OK;
}
}
return ERR_OK;
}
/* ---------------------------------------------------------------------------------------- */
/* -------------------------------------- Box method -------------------------------------- */
/* ---------------------------------------------------------------------------------------- */
struct My_NetList * VI_SMode_insert(struct My_NetList *head,struct My_NetList add)
{
struct My_NetList *p = NULL;
p = mymalloc(SRAMIN,sizeof(struct My_NetList));
if(p != NULL)
{
memcpy((char *)p,(char *)&add,sizeof(struct My_NetList));
p->col_next = head->col_next;
head->col_next->col_pre = p;
head->col_next = p;
head->col_next->col_pre = head;
return p;
}
return NULL;
}
int VI_SMode_deleted(struct My_NetList *head,struct tcp_pcb *socket)
{
struct My_NetList *p = NULL;
for(p = head->col_next ; p != head ; p = p->col_next)
{
if(p->socket == socket)
{
p->col_pre->col_next = p->col_next;
p->col_next->col_pre = p->col_pre;
myfree(SRAMIN,p);
return 0;
}
}
return -1;
}
int VI_CSMode_Broadcast(char *buffer , unsigned short len , char *name)
{
/* The buffer will be sent to this port */
unsigned char length,i;
struct My_NetList *p = NULL;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
/* First. Find this port. */
for(i = 0 ; i < length ; i++)
{
if(My_NetList[i].cs_mode == CS_MODE_CLIENT)
{
/* If it's a client. we should use remote port */
if(My_NetList[i].connect_state == ESTABLISHED && strcmp(My_NetList[i].name,name) == 0)
{
tcp_write(My_NetList[i].socket,buffer,len,TCP_WRITE_FLAG_COPY);
tcp_output(My_NetList[i].socket);
break;
}
}
else if(My_NetList[i].cs_mode == CS_MODE_SERVER)
{
/* If it's a server. we should use local port */
if(strcmp(My_NetList[i].name,name) == 0)
{
for(p = My_NetList[i].col_next ; p != &My_NetList[i] ; p = p->col_next)
{
/* send to all the third-party */
tcp_write(p->socket,buffer,len,TCP_WRITE_FLAG_COPY);
tcp_output(p->socket);
}
}
}
else
{
Dbg("It's a illegal C/S mode");
}
}
return 0;
}
int VI_Telenet_Broadcast(char *buffer , unsigned short len)
{
/* The buffer will be sent to this port */
unsigned char length,i;
struct My_NetList *p = NULL;
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
/* First. Find this port. */
for(i = 0 ; i < length ; i++)
{
if(My_NetList[i].cs_mode == CS_MODE_SERVER)
{
/* If it's a server. we should use local port */
if(My_NetList[i].cs_loport == 23)
{
for(p = My_NetList[i].col_next ; p != &My_NetList[i] ; p = p->col_next)
{
/* send to all the third-party */
if(p->usrdata.telnet_arg.verf_flag == true && p->usrdata.telnet_arg.Play)
{
if( p->usrdata.telnet_arg.Crlf ){
p->usrdata.telnet_arg.Crlf = false;
tcp_write(p->socket,"\r\n",2,TCP_WRITE_FLAG_COPY);
}
tcp_write(p->socket,buffer,len,TCP_WRITE_FLAG_COPY);
tcp_output(p->socket);
}
}
}
}
}
return 0;
}
void VI_CMode_IPParse(const char *name, struct ip_addr *ipaddr, void *arg)
{
struct My_NetList *Net_node;
Net_node = (struct My_NetList *)arg;
/* dns parse success. here load ip addr to node */
Net_node->cs_remoteip[3] = ipaddr->addr>>24;
Net_node->cs_remoteip[2] = ipaddr->addr>>16;
Net_node->cs_remoteip[1] = ipaddr->addr>>8;
Net_node->cs_remoteip[0] = ipaddr->addr;
}
/*
* Echo ( just for telnet )
*/
void VI_CSMode_StateEcho(char *buffer,unsigned short buffer_len)
{
unsigned char length,i;
char l_byTemparry[500];
struct My_NetList *p = NULL;
memset(buffer,0,buffer_len);
sprintf(buffer,"\r\n");
length = sizeof(My_NetList)/sizeof(My_NetList[0]);
for(i = 0 ; i < length ; i++)
{
if(My_NetList[i].cs_mode == CS_MODE_CLIENT)
{
sprintf(l_byTemparry,"+\t\tname:%s\r\n+\t\tmode:client\r\n+\t\tdns : %s\r\n+\t\tstate:%s\r\n+\t\tremote port:%d\r\n+\t\tHeatbeat:%d\r\n\r\n",\
My_NetList[i].name,My_NetList[i].dns,g_stEthstatus[My_NetList[i].connect_state],My_NetList[i].cs_rmport,My_NetList[i].Heatbeat);
strcat(buffer,l_byTemparry);
}
else
{
/* it's server */
sprintf(l_byTemparry,"+\t\tname:%s\r\n+\t\tmode:server\r\n+\t\tlocal port:%d\r\n\r\n",\
My_NetList[i].name,My_NetList[i].cs_loport);
strcat(buffer,l_byTemparry);
for(p = My_NetList[i].col_next ; p != &My_NetList[i] ; p = p->col_next)
{
sprintf(l_byTemparry,"+\t\t\tthird-party\r\n+\t\t\tname:%s\r\n+\t\t\tHeatbeat:%d\r\n\r\n",p->name,p->Heatbeat);
strcat(buffer,l_byTemparry);
}
}
}
}
My_Bussiness_Init_Register(VI_NetInit,VICON_BUSSINESS_INIT_LEVEL_4);
My_Platform_TimeSlice_Register(VI_NetReconnectCheck,VICON_PLATFORM_1S);
/******************* (C) COPYRIGHT 2019 Doon****************END OF FILE****/
My_TcpManager.h
/********************************************************************************************************
/ Doon OS-I
/ The Linux-app Wireless manager
/
/
/ (c) Copyright 2019-2023; Micrium, Inc.; ShenZhen, FL
/ All rights reserved. You may obtain a copy of the License at:.
/
/ https://me.youkuaiyun.com/weixin_40952498
/
/ File : My_NetManager.h
/ Version : V0.00.01
/ By : Doon
/ Date : 2019-July 2 Tuesday
/
/ For : STM32F407VET6
/ Mode : Thread mode
/ Toolchain : Source Insight 4.0
********************************************************************************************************/
#ifndef _MY_NETMANAGER_H_
#define _MY_NETMANAGER_H_
#include "project.h"
/* <! Client/Server Mode selection > */
#define CS_MODE_NOTDEF 0
#define CS_MODE_CLIENT 1 /* < C/S mode -> client > */
#define CS_MODE_SERVER 2 /* < C/S mode -> server > */
#define CS_MODE_THIRDP 3 /* < C/S mode -> third-party conn > */
/* <! User data length > */
#define USR_DATA_LENGTH 50
/* <! Heatbeat > */
#define HEATBEAT_NOCOUNT 0xffff
#define HEATBEAT_DEFAULT 180
typedef union
{
struct{
unsigned char usrname[10];
unsigned char password[10];
unsigned char verf_flag;
unsigned char verf_count;
unsigned char Play:1;
unsigned char Crlf:1;
unsigned char Idle:6;
}telnet_arg;
struct{
unsigned char mode;
unsigned char sessionkey[16];
}bosch_arg;
/* add usr code here */
unsigned char by[USR_DATA_LENGTH];
}My_NetUsrArg_Def;
/*
The netlist manager map blow to see. The row will be an arrary
but column will be a linked list
+------+ -next-> +------+ -next-> +------+ -next-> +------+
|server| |server| |client| |server|
+------+ <--pre- +------+ <-pre-- +------+ <-pre-- +------+
^ | ^ | ^ |
| v | v | v
+------+ +------+ +------+
|client| |client| |client|
+------+ +------+ +------+
^ |
| v
+------+
|client|
+------+
*/
typedef struct My_NetList
{
/* < Public variable > */
char name[32]; /* < The socket description > */
unsigned char cs_mode; /* < Client or server mode > */
unsigned short cs_rmport; /* < Port of remote socket > */
unsigned short cs_loport; /* < Port of local socket > */
const char *dns; /* < dns of connect object(server ignore) > */
unsigned char cs_remoteip[4]; /* < ip-addr of connect object(server ignore) > */
unsigned char connect_state; /* < Socket state > */
struct tcp_pcb *socket; /* < ...... > */
unsigned short buffer_length; /* < the app recv buffer length , will malloc auto > */
unsigned char keepalive; /* < TCP keepalive flag > */
unsigned char suspend; /* < suspend > */
unsigned short Heatbeat_Setting; /* < the setting value of heatbeat timer > */
unsigned short Heatbeat; /* < the heatbeat (if this number eaual 0xffff , the count didn't work) > */
/* < User variable > */
My_NetUsrArg_Def usrdata; /* */
err_t (*Parse)(struct My_NetList *node,char *buffer,unsigned short length); /* usr parse buffer handler */
err_t (*cf_handler)(struct My_NetList *node); /* connect failed handler */
struct My_NetList *row_next; // if we need dynamic expansion
struct My_NetList *row_pre;
struct My_NetList *col_next;
struct My_NetList *col_pre;
}My_NetList_Def;
extern My_NetList_Def My_NetList[];
void VI_NetInit(void);
void VI_NetRelease(void);
int VI_CSMode_Broadcast(char *buffer , unsigned short len , char *name);
void VI_CSMode_StateEcho(char *buffer,unsigned short buffer_len);
int VI_Telenet_Broadcast(char *buffer , unsigned short len); // for the debug.
struct My_NetList *VI_Net_Getnode(char *name);
int VI_Net_Resume(char *name);
int VI_Net_Suspend(char *name);
int VI_Net_shutdown(char *name);
int VI_Net_HBReset(char *name);
#endif
部分常用的库文件我都添加在"project.h"中,稍后会贴出。
设计思路是想使用二维矩阵链表来对连接进行管理,但是最终我并没有使用动态而是使用了静态数组来进行填表,如果大家有需要可以修改成动态的。- -不知道为什么这里贴出来的代码非常不美观,不太会玩这个编辑器。
下面是我project.h的内容,工程并不是特别大,就直接在一个地方进行管理了,并且附的带了一些调试的接口:
/********************************************************************************************************
/ Doon OS-I
/ The Doon-app Wireled manager
/
/
/ (c) Copyright 2019-2023; Micrium, Inc.; ShenZhen, FL
/ All rights reserved. You may obtain a copy of the License at:.
/
/ https://me.youkuaiyun.com/weixin_40952498
/
/ File : My project.
/ Version : V0.00.01
/ By : Doon
/ e-mail : 1176964408@qq.com
/ Date : 2019-July 2 Tuesday
/
/ For : STM32F407VET6
/ Mode : Thread mode
/ Toolchain : Source Insight 4.0
********************************************************************************************************/
#ifndef __PROJECT_H
#define __PROJECT_H
/*************************************************************************
*@ type definition
**************************************************************************/
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include "stdint.h"
#include "stm32f4xx_usart.h"
#include "stm32f4xx.h"
#include "stm32f4xx_exti.h"
/* ---------- My OS ---------- */
#include "Doon_Type_Define.h"
#include "LibMacRo.h"
#include "MyOS_Init.h"
#include "MyOS_Tick.h"
#include "MyOS_Handler.h"
#include "MyOS_Core.h"
#include "malloc.h"
#include "rbtrees.h"
/* ---------- My Driver ---------- */
#include "led.h"
#include "key.h"
#include "usart.h"
#include "spi.h"
#include "dp83848l.h"
#include "timer.h"
#include "MacDr.h"
#include "can.h"
#include "rng.h"
#include "iwdg.h"
/* ---------- My Eth driver ---------- */
#include "lwip/opt.h"
#include "lwip_comm.h"
#include "lwip/lwip_sys.h"
#include "lwip/udp.h"
#include "lwip/api.h"
#include "lwipopts.h"
#include "netif.h"
#include "lwip/sockets.h"
#include "lwip/tcp.h"
#include "lwip/err.h"
#include "lwip/dns.h"
#include "lwip/raw.h"
#include "lwip/def.h"
#include "lwip/mem.h"
#include "lwip/memp.h"
#include "lwip/snmp.h"
#include "lwip/tcp_impl.h"
#include "lwip/debug.h"
#include "lwip/stats.h"
/* ---------- My Device ---------- */
#include "My_DevAbility.h"
#include "My_CAN.h"
#include "My_ExFlash.h"
#include "My_Modbus.h"
#include "My_Power.h"
#include "My_Telnet.h"
#include "My_Led.h"
#include "My_Scene.h"
#include "My_Time.h"
#include "My_DevInfo.h"
#include "My_Rs485.h"
#include "My_Tcp.h"
#include "My_Udp.h"
#include "My_Http.h"
#include "My_Cloud.h"
#include "My_Report.h"
#include "My_NetManager.h"
#include "my_p2m.h"
#include "p2m_configure.h"
#include "p2m_control.h"
#include "p2m_read.h"
#include "My_Json.h"
#include "Can_Update_api.h"
#include "My_Command.h"
/**************************************************************************
* printf color pain
* none = "\033[0m"
* black = "\033[0;30m"
* dark_gray = "\033[1;30m"
* blue = "\033[0;34m"
* light_blue = "\033[1;34m"
* green = "\033[0;32m"
* light_green = "\033[1;32m"
* cyan = "\033[0;36m"
* light_cyan = "\033[1;36m"
* red = "\033[0;31m"
* light_red = "\033[1;31m"
* purple = "\033[0;35m"
* light_purple = "\033[1;35m"
* brown = "\033[0;33m"
* yellow = "\033[1;33m"
* light_gray = "\033[0;37m"
* white = "\033[1;37m"
****************************************************************************/
#define DBG_COLOR_NONE "\033[0m"
#define DBG_COLOR_BLACK "\033[0;30m"
#define DBG_COLOR_DARK_GRAY "\033[1;30m"
#define DBG_COLOR_BLUE "\033[0;34m"
#define DBG_COLOR_LIGHT_BLUE "\033[1;34m"
#define DBG_COLOR_GREEN "\033[0;32m"
#define DBG_COLOR_LIGHT_GREEN "\033[1;32m"
#define DBG_COLOR_CYAN "\033[0;36m"
#define DBG_COLOR_LIGHT_CYAN "\033[1;36m"
#define DBG_COLOR_RED "\033[0;31m"
#define DBG_COLOR_LIGHT_RED "\033[1;31m"
#define DBG_COLOR_PURPLE "\033[0;35m"
#define DBG_COLOR_LIGHT_PURPLE "\033[1;35m"
#define DBG_COLOR_BROWN "\033[0;33m"
#define DBG_COLOR_YELLOW "\033[1;33m"
#define DBG_COLOR_LIGHT_GRAY "\033[0;37m"
#define DBG_COLOR_WHITE "\033[1;37m"
/**
* I don't want to recv the warning blow diagnostic messages number
*/
#pragma diag_suppress 550
/**
* Doon_Dbg == 1: if you wanna open the main switch of debug
*/
#ifndef Doon_Dbg
#define Doon_Dbg 1
#endif
#ifndef Tlenet_Dbg
#define Tlenet_Dbg 1
#endif
#ifndef USART_Dbg
#define USART_Dbg 0
#endif
#if Doon_Dbg
#if Tlenet_Dbg
#if USART_Dbg
#define Dbg(fmt,args...) do{\
/*if(MyOS_Status.Telnet_Status == OS_CONN_CONNECTED){*/\
snprintf(Telnet_Send_Buff,TELNET_SEND_BUFF_SIZE,DBG_COLOR_YELLOW "Doon Dbg " DBG_COLOR_NONE " %s %d: " fmt "\r\n",__FILE__,__LINE__, ## args);\
VI_Telenet_Broadcast(Telnet_Send_Buff,strlen(Telnet_Send_Buff));\
/*}else{\
printf(DBG_COLOR_YELLOW"Doon Dbg" DBG_COLOR_NONE " %s %d: " fmt "\r\n",__FILE__,__LINE__, ## args);\
}*/\
}while(0);
#else
#define Dbg(fmt,args...) do{\
/*if(MyOS_Status.Telnet_Status == OS_CONN_CONNECTED){*/\
snprintf(Telnet_Send_Buff,TELNET_SEND_BUFF_SIZE,DBG_COLOR_YELLOW "Doon Dbg " DBG_COLOR_NONE " %s %d: " fmt "\r\n",__FILE__,__LINE__, ## args);\
VI_Telenet_Broadcast(Telnet_Send_Buff,strlen(Telnet_Send_Buff));\
/*}else{\
printf(DBG_COLOR_YELLOW"Doon Dbg" DBG_COLOR_NONE " %s %d: " fmt "\r\n",__FILE__,__LINE__, ## args);\
}*/\
}while(0);
#endif
#else
#if USART_Dbg
#define Dbg(fmt,args...) do{\
printf(DBG_COLOR_YELLOW"Doon Dbg" DBG_COLOR_NONE " %s %d: " fmt "\r\n",__FILE__,__LINE__, ## args);\
}while(0);
#else
#define Dbg(fmt,args...) /* empty printf */
#endif
#endif
#else
#define Dbg(fmt,args...) /* empty printf */
#endif
//#define REGISTER_CMD(name,maxargs,rep,cmd,usage,help) \ const cmd_tbl_t strcmd_##name __attribute__ ((section ("cmd"))) = {#name, maxargs, rep, cmd, usage,help}
#endif
/******************* (C) COPYRIGHT 2018 Doon****************END OF FILE****/
仅供参考。
中文使用说明:
/********************************************************************************************************
/ Doon OS-I
/ The Doon-app Wireled manager
/
/
/ (c) Copyright 2019-2023; Micrium, Inc.; ShenZhen, FL
/ All rights reserved. You may obtain a copy of the License at:.
/
/ https://me.youkuaiyun.com/weixin_40952498
/
/ File : My_TcpManager.
/ Version : V0.00.01
/ By : Doon
/ e-mail : 1176964408@qq.com
/ Date : 2019-July 2 Tuesday
/
/ For : STM32F407VET6
/ Mode : Thread mode
/ Toolchain : Source Insight 4.0
********************************************************************************************************/
My Net 框架用例
结构如下:
/*
The netlist manager map blow to see. The row will be an arrary
but column will be a linked list
|------| -next-> |------| -next-> |------| -next-> |------|
|server| |server| |client| |server|
|------| <--pre- |------| <-pre-- |------| <-pre-- |------|
^ | ^ | ^ |
| v | v | v
|------| |------| |------|
|client| |client| |client|
|------| |------| |------|
*/
typedef struct My_NetList
{
/* < Public variable > */
char name[32]; /* < 该socket 名字(寻找唯一路径) > */
unsigned char cs_mode; /* < 该socket模式(可选服务端或者客户端) > */
unsigned short cs_rmport; /* < 该socket远端端口号 > */
unsigned short cs_loport; /* < 该socket本地端口号 > */
const char *dns; /* < 域名(仅有客户端存在域名,服务端暂不支持) > */
unsigned char cs_remoteip[4]; /* < 远端ip地址(仅有客户端支持,服务端不支持远端ip) > */
unsigned char connect_state; /* < socket连接状态 > */
struct tcp_pcb *socket; /* < socket > */
unsigned short buffer_length; /* < 可自动生成接收buffer的长度 > */
unsigned char keepalive; /* < TCP 保活机制使能位 > */
unsigned char suspend; /* < 该socket挂起标志 > */
unsigned short Heatbeat_Setting; /* < 心跳设置周期(根据各协议心跳不一致,需要用户手动调用心跳Reset API) > */
unsigned short Heatbeat; /* < 心跳剩余时间(心跳) > */
/* < User variable > */
My_NetUsrArg_Def usrdata; /* < 用户自定义数据 > */
err_t (*Parse)(struct My_NetList *node,char *buffer,unsigned short length); /* 用户解析回调函数 */
err_t (*cf_handler)(struct My_NetList *node); /* 连接失败回调函数(客户端有效) */
struct My_NetList *row_next; // if we need dynamic expansion
struct My_NetList *row_pre;
struct My_NetList *col_next;
struct My_NetList *col_pre;
}My_NetList_Def;
目前横向使用的是静态数组,纵向使用的环回双向链表,当网关作为服务端时,链表生效,接受第三方设备连入。当网关作为客户端时,链表不生效。(当横向可配置生成时,需修改为横向双向环回链表)
PA:第三方客户端连入网关的name默认为 "ip addr-port" -> "192.168.82.123-10108"(需唯一,用户可自行修改socket name,可修改为第三方网关sn等等)
/* < -------------- API 使用说明 -------------- > */
/*
描述:无条件广播(用户可以该API为原型完成自定义条件广播,参考Telnet广播)
buffer: 广播的buffer
len: buffer的长度
name: socket名字(当socket名字为服务端时,将发送给该端口下所有连接的客户端,
当socket名字为客户端时,只发送给连接的服务端
当socket名字为第三方客户端时,只发送给该)
*/
int VI_CSMode_Broadcast(char *buffer , unsigned short len , char *name);
/*
描述:获取该name节点的所有信息
*/
struct My_NetList *VI_Net_Getnode(char *name);
/*
描述:挂起该socket节点,被挂起后的节点将不再进行自动重连(客户端)
*/
int VI_Net_Suspend(char *name);
/*
描述:恢复该socket节点,被恢复的节点将会自动重连(客户端)
*/
int VI_Net_Resume(char *name);
/*
描述:关闭该socket节点,可填客户端,服务端,第三方节点name
客户端:关闭客户端,若未挂起该socket,将自动重连
服务端:关闭服务端下所有第三方连接,不关闭监听,第三方仍然可连入(可完善)
第三方连接:仅关闭该第三方socket,不影响其他socket。
*/
int VI_Net_shutdown(char *name);
/*
描述:重置心跳,用户协议收到心跳包后应该使用api重置心跳时间
*/
int VI_Net_HBReset(char *name);