ST意法半导体
直播中

刘浩

7年用户 1164经验值
私信 关注
[问答]

请问如何向客户端发送数据LwIP tcp服务器?

我有 tcp_server 的基本应用程序。
  • void tcp_echoserver_init( uint16_t port)
  • {
  •          tcp_echoserver_PCB = tcp_new();
  •    if ( tcp_echoserver_pcb != NULL)
  •    {
  •      err_t err;
  •      /* bind echo_pcb to port (ECHO protocol) */
  •      err = tcp_bind( tcp_echoserver_pcb, IP_ADDR_ANY, port);
  •      if (err == ERR_OK)
  •      {
  •        /* start tcp listening for echo_pcb */
  •             tcp_echoserver_pcb = tcp_listen( tcp_echoserver_pcb );
  •        /* initialize LwIP tcp_accept callback function */
  •             tcp_accept( tcp_echoserver_pcb , tcp_echoserver_accept);
  •      }
  •      else
  •      {
  •        /* deallocate the pcb */
  •        memp_free(MEMP_TCP_PCB, tcp_echoserver_pcb );
  •      }
  •    }
  • }
  • static err_t tcp_echoserver_accept(void *arg, struct tcp_pcb *newpcb, err_t err)
  • {
  •    err_t ret_err;
  •    struct echoserver *es;
  •    LWIP_UNUSED_ARG(arg);
  •    LWIP_UNUSED_ARG(err);
  •    /* set priority for the newly accepted tcp connection newpcb */
  •    tcp_setprio(newpcb, TCP_PRIO_MIN);
  •    /* allocate structure es to maintain tcp connection informations */
  •    es = (struct echoserver *)mem_malloc(sizeof(struct echoserver));
  •    if (es != NULL)
  •    {
  •      es->state = ES_ACCEPTED;
  •      es->pcb = newpcb; //newpcb;
  •      es->retries = 0;
  •      es->p = NULL;
  •      /* pass newly allocated es structure as argument to newpcb */
  •      tcp_arg(newpcb, es);
  •      /* initialize lwip tcp_recv callback function for newpcb  */
  •      tcp_recv(newpcb, tcp_echoserver_recv);
  •      /* initialize lwip tcp_err callback function for newpcb  */
  •      tcp_err(newpcb, tcp_echoserver_error);
  •      /* initialize lwip tcp_poll callback function for newpcb */
  •      tcp_poll(newpcb, tcp_echoserver_poll, 0);
  •      ret_err = ERR_OK;
  •    }
  •    else
  •    {
  •      /*  close tcp connection */
  •      tcp_echoserver_connection_close(newpcb, es);
  •      /* return memory error */
  •      ret_err = ERR_MEM;
  •    }
  •    return ret_err;
  • }
  • static err_t tcp_echoserver_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
  • {
  •    struct echoserver *es;
  •    err_t ret_err;
  •    LWIP_ASSERT("arg != NULL",arg != NULL);
  •    es = (struct echoserver *)arg;
  •    /* if we receive an empty tcp frame from client => close connection */
  •    if (p == NULL)
  •    {
  •      /* remote host closed connection */
  •      es->state = ES_CLOSING_SERVER;
  •      if(es->p == NULL)
  •      {
  •         /* we're done sending, close connection */
  •         tcp_echoserver_connection_close(tpcb, es);
  •      }
  •      else
  •      {
  •        /* we're not done yet */
  •        /* acknowledge received packet */
  •        tcp_sent(tpcb, tcp_echoserver_sent);
  •        /* send remaining data*/
  •        tcp_echoserver_send(tpcb, es);
  •      }
  •      ret_err = ERR_OK;
  •    }
  •    /* else : a non empty frame was received from client but for some reason err != ERR_OK */
  •    else if(err != ERR_OK)
  •    {
  •      /* free received pbuf*/
  •      if (p != NULL)
  •      {
  •        es->p = NULL;
  •        pbuf_free(p);
  •      }
  •      ret_err = err;
  •    }
  •    else if(es->state == ES_ACCEPTED)
  •    {
  •      /* first data chunk in p->payload */
  •      es->state = ES_RECEIVED_SERVER;
  •      /* store reference to incoming pbuf (chain) */
  •      es->p = p;
  •      /* initialize LwIP tcp_sent callback function */
  •      tcp_sent(tpcb, tcp_echoserver_sent);
  •      /* send back the received data (echo) */
  •      tcp_echoserver_send(tpcb, es);
  •      ret_err = ERR_OK;
  •    }
  •    else if (es->state == ES_RECEIVED_SERVER)
  •    {
  •      /* more data received from client and previous data has been already sent*/
  •      if(es->p == NULL)
  •      {
  •        es->p = p;
  •        /* send back received data */
  •        tcp_echoserver_send(tpcb, es);
  •      }
  •      else
  •      {
  •        struct pbuf *ptr;
  •        ptr = es->p;
  •        pbuf_chain(ptr,p);
  •      }
  •      ret_err = ERR_OK;
  •    }
  •    else if(es->state == ES_CLOSING)
  •    {
  •      /* odd case, remote side closing twice, trash data */
  •      tcp_recved(tpcb, p->tot_len);
  •      es->p = NULL;
  •      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;
  • }
  • static void tcp_echoserver_error(void *arg, err_t err)
  • {
  •    struct tcp_echoserver_struct *es;
  •    LWIP_UNUSED_ARG(err);
  •    es = (struct tcp_echoserver_struct *)arg;
  •    if (es != NULL)
  •    {
  •      /*  free es structure */
  •      mem_free(es);
  •    }
  • }
  • static err_t tcp_echoserver_poll(void *arg, struct tcp_pcb *tpcb)
  • {
  •    err_t ret_err;
  •    struct echoserver *es;
  •    es = (struct echoserver *)arg;
  •    if (es != NULL)
  •    {
  •      if (es->p != NULL)
  •      {
  •        tcp_sent(tpcb, tcp_echoserver_sent);
  •        /* there is a remaining pbuf (chain) , try to send data */
  •        tcp_echoserver_send(tpcb, es);
  •      }
  •      else
  •      {
  •        /* no remaining pbuf (chain)  */
  •        if(es->state == ES_CLOSING_SERVER)
  •        {
  •          /*  close tcp connection */
  •          tcp_echoserver_connection_close(tpcb, es);
  •        }
  •      }
  •      ret_err = ERR_OK;
  •    }
  •    else
  •    {
  •      /* nothing to be done */
  •      tcp_abort(tpcb);
  •      ret_err = ERR_ABRT;
  •    }
  •    return ret_err;
  • }
  • static err_t tcp_echoserver_sent(void *arg, struct tcp_pcb *tpcb, u16_t len)
  • {
  •    struct echoserver *es;
  •    LWIP_UNUSED_ARG(len);
  •    es = (struct echoserver *)arg;
  •    es->retries = 0;
  •    if(es->p != NULL)
  •    {
  •      /* still got pbufs to send */
  •      tcp_sent(tpcb, tcp_echoserver_sent);
  •      tcp_echoserver_send(tpcb, es);
  •    }
  •    else
  •    {
  •      /* if no more data to send and client closed connection*/
  •      if(es->state == ES_CLOSING_SERVER)
  •        tcp_echoserver_connection_close(tpcb, es);
  •    }
  •    return ERR_OK;
  • }
  • static void tcp_echoserver_send(struct tcp_pcb *tpcb, struct echoserver *es)
  • {
  •    struct pbuf *ptr;
  •    err_t wr_err = ERR_OK;
  •         while ( (wr_err == ERR_OK) &&
  •           (es->p != NULL) &&
  •           (es->p->len <= tcp_sndbuf(tpcb)))
  •    {
  •      /* get pointer on pbuf from es structure */
  •      ptr = es->p;
  •      /* enqueue data for transmission */
  •              wr_err = tcp_write(tpcb, ptr->payload, ptr->len, 1);
  •      if (wr_err == ERR_OK)
  •      {
  •        u16_t plen;
  •        u8_t freed;
  •        plen = ptr->len;
  •        /* continue with next pbuf in chain (if any) */
  •        es->p = ptr->next;
  •        if(es->p != NULL)
  •        {
  •          /* increment reference count for es->p */
  •          pbuf_ref(es->p);
  •        }
  •       /* chop first pbuf from chain */
  •        do
  •        {
  •          /* try hard to free pbuf */
  •          freed = pbuf_free(ptr);
  •        }
  •        while(freed == 0);
  •       /* we can read more data now */
  •       tcp_recved(tpcb, plen);
  •     }
  •     else if(wr_err == ERR_MEM)
  •     {
  •        /* we are low on memory, try later / harder, defer to poll */
  •       es->p = ptr;
  •     }
  •     else
  •     {
  •       /* other problem ?? */
  •     }
  •    }
  • }
  • static void tcp_echoserver_connection_close(struct tcp_pcb *tpcb, struct echoserver *es)
  • {
  •    /* remove all callbacks */
  •    tcp_arg(tpcb, NULL);
  •    tcp_sent(tpcb, NULL);
  •    tcp_recv(tpcb, NULL);
  •    tcp_err(tpcb, NULL);
  •    tcp_poll(tpcb, NULL, 0);
  •    /* delete es structure */
  •    if (es != NULL)
  •    {
  •      mem_free(es);
  •    }
  •    /* close tcp connection */
  •    tcp_close(tpcb);
  • }
我使用这个函数,它可以在从客户端接收到数据时发送并回显它,但是如果我调用 tcp_echoserver_send( newpcb, &es ); 代码的任何地方,无法发送。

我遇到了如下断言,
C:/Works/Projects/STM32Cube_FW_F2_V1.9.0/Middlewares/Third_Party/LwIP/src/core/tcp_out.c 中第 414 行的断言“tcp_write: invalid pcb”失败
任何帮助将不胜感激,谢谢。


回帖(1)

何瑾

2022-12-27 10:21:08
我找到了解决方案。问题是 struct echoserver *es 在 accept 函数中声明为局部变量。我使用全局变量并且它工作正常。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分