lwip raw tcp/client 实现

stm32 lwip tcp客户端和服务端编写。


lwip提供的各种回调函数

1.tcp_new()函数:
	用来返回一个struct tcp_pcb* 的一个指针。

2.设置tcp/ip的保活设置。
	 client_pcb->so_options |= SOF_KEEPALIVE;
         client_pcb->keep_idle = 50000;	   // ms   tcp连接上5秒之后,发送第一keep_alive数据包。
         client_pcb->keep_intvl = 20000;   // ms   以后每隔2秒发送一个keep_alive数据包。
         client_pcb->keep_cnt = 5;	   // 如果联系5次没有收到对方回应的keep_alive数据包。则认为已经断开连接。

3. err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,
      err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))

	函数功能:
		用来连接到一个指定的tcp服务端。

	参数一:
		tcp_new()函数的返回值。作为该函数的第一参数。
	
	参数二:
		要连接到那个ip地址上,可以使用下面的这个宏函数进行处理。
		
		IP4_ADDR( &DestIPaddr, *destip, *(destip+1),*(destip+2), *(destip+3));

		#define IP4_ADDR(ipaddr, a,b,c,d) \
		(ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \
                               ((u32_t)((b) & 0xff) << 16) | \
                               ((u32_t)((c) & 0xff) << 8) | \
                                (u32_t)((d) & 0xff))
	参数三:连接到tcp服务端的端口号  2000,
	
	参数四:它是一个函数指针。这个函数指针说明在tcp连接上服务端之后,会调用该函数。


4.void tcp_err(struct tcp_pcb *pcb, void (* errf)(void *arg, err_t err))
	
	函数的功能:
		连接出错的时候。进行错误处理的函数。
	参数一:
		用来描述tcp连接的一个结构体。
	参数二:
		用来处理错误的函数。当连接出现异常的时候。会调用这个函数。

5.void tcp_arg(struct tcp_pcb *pcb, void *arg)
	功能:
		提供一种可以让应用程序传递参数给回调函数的方法。
	参数一:
		用来描述tcp连接的一个结构体。
	参数二:
		应用程序提供的一个结构体。他可以保护tcp的状态,或者tcp要发送的数据等信息。

6.static err_t tcp_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
	函数功能:
		当接收到数据的时候。对接收的数据进行处理。
	参数一:
		该参数是通过tcp_arg()函数传入的。
	参数二: 
		用来描述tcp连接的一个结构体。
	参数三:
		接收到的数据都存放在这个pbuf中。
	参数四:
		err,它说明了这次tcp连接过程中是否出现异常。如果他的值为ERR_OK说明正常。
	
	注释:如果接收到的 p 等于空的话。说明服务端主动关闭连接了,那么需要关闭这个socket,连接。
	并启动一个time。定时的重新连接服务端socket.

7. void tcp_recved(struct tcp_pcb *pcb, u16_t len)
	函数功能:
	当tcp_client_recv()函数调用正常的话。则可用使用该方法进行数据接收方法。
	参数一:
		用来描述tcp连接的一个结构体。
	参数二:
		要接收的数据长度。一般情况下可以认为是p->tot_len。

	

最后把函数代码该贴上。
err_t tcp_client_connect(const uint8_t *destip, uint16_t port)
{
  struct tcp_pcb *client_pcb;
  struct ip_addr DestIPaddr;
  err_t err = ERR_OK;

  /* create new tcp pcb */
  client_pcb = tcp_new();
  client_pcb->so_options |= SOF_KEEPALIVE;
 #if 1
  client_pcb->keep_idle = 50000;	   // ms
  client_pcb->keep_intvl = 20000;	   // ms
  client_pcb->keep_cnt = 5; 
 #endif	   
  if (client_pcb != NULL)
  {

   
   IP4_ADDR( &DestIPaddr, *destip, *(destip+1),*(destip+2), *(destip+3) );

    /* connect to destination address/port */
    err = tcp_connect(client_pcb,&DestIPaddr,port,tcp_client_connected);
   
    tcp_err(client_pcb,tcp_errf);
    
  }
  return err;
  
}


static err_t tcp_client_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
   
    if(es == NULL) es = (struct client *)mem_malloc(sizeof(struct client));
    switch(err){
        case ERR_OK:  
          es->pcb = tpcb;                                  /*设置当前的状态为连接状态?*/  
          es->p_tx = NULL;
          es->state = ES_CONNECTED;  
          tcp_arg(tpcb, es);                       /*把当前的参数传给所有的回调函数?   */ 
          tcp_recv(tpcb, tcp_client_recv);
        
          break ;
       case ERR_MEM :
           tcp_client_connection_close(tpcb, es);                
          break ;
       default :
           break ;
           
   }
   return err;
}


static void tcp_errf(void *arg,err_t err){
    printf("\r\ntcp_errf be called...\r\n");
    if(es == NULL){
        es = (struct client *)mem_malloc(sizeof(struct client));
        es = (struct client *)arg;
    }
    if(err == ERR_OK ){
          /* No error, everything OK. */
          return ;
     }   
    switch(err)
    { 
        case ERR_MEM:                                            /* Out of memory error.     */
            printf("\r\n ERR_MEM   \r\n");
            break;  
        case ERR_BUF:                                            /* Buffer error.            */
            printf("\r\n ERR_BUF   \r\n");
            break;
        case  ERR_TIMEOUT:                                       /* Timeout.                 */
            printf("\r\n ERR_TIMEOUT   \r\n");
            break;
        case ERR_RTE:                                            /* Routing problem.         */      
             printf("\r\n ERR_RTE   \r\n");
            break;
       case ERR_ISCONN:                                          /* Already connected.       */
             printf("\r\n ERR_ISCONN   \r\n");
            break;
        case ERR_ABRT:                                           /* Connection aborted.      */
            printf("\r\n ERR_ABRT   \r\n");
            break;
        case ERR_RST:                                            /* Connection reset.        */     
            printf("\r\n ERR_RST   \r\n");
            break;
        case ERR_CONN:                                           /* Not connected.           */
          printf("\r\n ERR_CONN   \r\n");
            break;
        case ERR_CLSD:                                           /* Connection closed.       */
            printf("\r\n ERR_CLSD   \r\n");
            break;
        case ERR_VAL:                                            /* Illegal value.           */
           printf("\r\n ERR_VAL   \r\n");
           return;
        case ERR_ARG:                                            /* Illegal argument.        */
            printf("\r\n ERR_ARG   \r\n");
            return;
        case ERR_USE:                                            /* Address in use.          */
           printf("\r\n ERR_USE   \r\n");
           return; 
        case ERR_IF:                                             /* Low-level netif error    */
            printf("\r\n ERR_IF   \r\n");
            break;
        case ERR_INPROGRESS:                                     /* Operation in progress    */
            printf("\r\n ERR_INPROGRESS   \r\n");
            break;

    }
   es->state  = ES_CLOSING;
   err_process();
}
    
    
/**
  * @brief tcp_receiv callback
  * @param arg: argument to be passed to receive callback 
  * @param tpcb: tcp connection control block 
  * @param err: receive error code 
  * @retval err_t: retuned error  
  */
static err_t tcp_client_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{ 
  struct client *es;
  err_t ret_err;
  LWIP_ASSERT("arg != NULL",arg != NULL);
  es = (struct client *)arg;
  if (p == NULL)
  {
    /* remote host closed connection */
    es->state = ES_CLOSING;
    if(es->p_tx == NULL)
    {
       /* we're done sending, close connection */
       tcp_client_connection_close(tpcb, es);
    }
    ret_err = ERR_OK;
  }   
  else if(err != ERR_OK)
  {
    /* free received pbuf*/
    if (p != NULL)
    {
      pbuf_free(p);
    }
    ret_err = err;
  }
  else if(es->state == ES_CONNECTED)
  {  
    /* Acknowledge data reception */
    tcp_recved(tpcb, p->tot_len);                   //获取p中的数据。

    memset(recevRxBufferTcpEth,0x00,TCPREVDATALEN);
    if(p->len > TCPREVDATALEN){    
        p->len= TCPREVDATALEN;    
    }
    memcpy(&recevRxBufferTcpEth,p->payload,p->len);
    tcpRecevieFlag  = 1;                    //将tcp设置为1.说明接收到了服务端的数据。
    pbuf_free(p);                   
    ret_err = ERR_OK;   
  }
  /* data received when connection already closed */
  else
  {
    /* Acknowledge data reception */
    tcp_recved(tpcb, p->tot_len);
    
    /* free pbuf and do nothing */
    pbuf_free(p);
    ret_err = ERR_OK;
  }
  return ret_err;
}


/**
  * @brief function used to send data
  * @param  tpcb: tcp control block
  * @param  es: pointer on structure of type client containing info on data 
  *             to be sent
  * @retval None 
  */
void tcp_client_send(struct tcp_pcb *tpcb, struct client * es)
{
  struct pbuf *ptr;
  err_t wr_err = ERR_OK; 
  while ((wr_err == ERR_OK) &&
         (es->p_tx != NULL) && 
         (es->p_tx->len <= tcp_sndbuf(tpcb)))
  {
    /* get pointer on pbuf from es structure */
    ptr = es->p_tx;

    wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
    
    if (wr_err == ERR_OK)
    { 
      /* continue with next pbuf in chain (if any) */
      es->p_tx = ptr->next;
      
      if(es->p_tx != NULL)
      {
      /* increment reference count for es->p */
        pbuf_ref(es->p_tx);
      }
      pbuf_free(ptr);
   }
   else if(wr_err == ERR_MEM)
   {
      /* we are low on memory, try later, defer to poll */
     es->p_tx = ptr;                                                    
   }
   else
   {
     es->p_tx = ptr;    
     /* other problem ?? */
   }
  }
}


//user send message 
u8_t tcp_send_message(void *msg, uint16_t len){
    u8_t  count = 0;
    struct pbuf *p;  
    if(es->state != ES_CONNECTED)  return -1;
    if(es->p_tx == NULL){
        
          es->p_tx  = pbuf_alloc(PBUF_TRANSPORT,len,PBUF_RAM);          
          pbuf_take( es->p_tx , (char*)msg, len);
    }
    tcp_client_send(es->pcb,es);
    return 1;
}




/**
  * @brief This function is used to close the tcp connection with server
  * @param tpcb: tcp connection control block
  * @param es: pointer on client structure
  * @retval None
  */
static void tcp_err_close()
{
  /* remove callbacks */
  tcp_recv(es->pcb, NULL);
  
  if (es != NULL)
  {
  	if(es->p_tx != NULL){
		pbuf_free(es->p_tx);
  	}
	if (es->pcb != NULL) {
		 tcp_close(es->pcb);
	}
    mem_free(es);
  }
}


static void tcp_client_connection_close()
{
  /* remove callbacks */
  tcp_recv(es->pcb, NULL);
  if (es != NULL)
  {
  	if(es->p_tx != NULL){
		pbuf_free(es->p_tx);
  	}
	if (es->pcb != NULL) {
		  /* close tcp connection */
		 tcp_close(es->pcb);
	}
    mem_free(es);
    es = NULL;
  }
  set_timer4_countTime(TIMER_5000MS);
}

//错误处理函数。当tcp连接发送错误的时候。调用该函数。
static void err_process(){
	connet_flag++;
	 if(connet_flag<= 3){
		set_timer4_countTime(TIMER_5000MS);
	 }
	 if(connet_flag>3){	   
		 connet_flag = 4;
		set_timer4_countTime(TIMER_10000MS);
	 }
}
//定时时间到的时候。调用该方法重连。
void reconnet_tcp_timer(){
	 if(es != NULL){
		tcp_err_close(es->pcb, es );
		tcp_client_connect(ip_des,destcp_port);
	 }else{
		tcp_client_connect(ip_des,destcp_port);
	 }	
}
 //用来处理数据的方法,具体的业务数据。
int W301ProcessRecvTcpData(){
  
}

  • 6
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值