物联网LWIP网络开发 TCP/IP设计原理12.3 lwIP消息处理机制

lwIP消息处理机制

数据包消息处理

物联网LWIP网络开发 TCP/IP设计原理12.3 lwIP消息处理机制_第1张图片

tcpip_input

/**
 * @ingroup lwip_os
 * Pass a received packet to tcpip_thread for input processing with
 * ethernet_input or ip_input. Don't call directly, pass to netif_add()
 * and call netif->input().
 *
 * @param p the received packet, p->payload pointing to the Ethernet header or
 *          to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or
 *          NETIF_FLAG_ETHERNET flags)
 * @param inp the network interface on which the packet was received
 */
err_t
tcpip_input(struct pbuf *p, struct netif *inp)
{
#if LWIP_ETHERNET
  if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) {
    return tcpip_inpkt(p, inp, ethernet_input);
  } else
#endif /* LWIP_ETHERNET */
  return tcpip_inpkt(p, inp, ip_input);
}

tcpip_inpkt

/**
 * Pass a received packet to tcpip_thread for input processing
 *
 * @param p the received packet
 * @param inp the network interface on which the packet was received
 * @param input_fn input function to call
 */
err_t
tcpip_inpkt(struct pbuf *p, struct netif *inp, netif_input_fn input_fn)
{
//tcpip内核是否上锁,这时候 我们的tcpip_thread 不能用
#if LWIP_TCPIP_CORE_LOCKING_INPUT
  err_t ret;
  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_inpkt: PACKET %p/%p\n", (void *)p, (void *)inp));
  LOCK_TCPIP_CORE();
  //直接调用输入解析函数
  ret = input_fn(p, inp);
  UNLOCK_TCPIP_CORE();
  return ret;
#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */
  //创建消息指针
  struct tcpip_msg *msg;
  //创建消息的目的就是为了发送消息邮箱,这里需要判断消息邮箱是否有效
  LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox));
  //分配消息的实际内存
  msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
  if (msg == NULL) {
    return ERR_MEM;
  }
  //消息类型属于数据消息
  msg->type = TCPIP_MSG_INPKT;
  msg->msg.inp.p = p;
  msg->msg.inp.netif = inp;
  msg->msg.inp.input_fn = input_fn;
  //发送消息到消息邮箱
  if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
    //释放消息内存
    memp_free(MEMP_TCPIP_MSG_INPKT, msg);
    return ERR_MEM;
  }
  return ERR_OK;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
}

API消息处理

物联网LWIP网络开发 TCP/IP设计原理12.3 lwIP消息处理机制_第2张图片

api_msg

/** This struct includes everything that is necessary to execute a function
    for a netconn in another thread context (mainly used to process netconns
    in the tcpip_thread context to be thread safe). */
struct api_msg {
  /* 大家可以理解为是一个socket,这个接口要表示很多信息,用一个结构体进行封装 */
  struct netconn *conn;
  /** 消息处理函数的返回值 */
  err_t err;
  /** Depending on the executed function, one of these union members is used */
  union {
    /** 用于网络数据发送 ---- write */
    struct netbuf *b;
    /** 相当于sockket */
    struct {
      u8_t proto;
    } n;
    /** 
    
    	bind
    	connect
    */
    struct {
      API_MSG_M_DEF_C(ip_addr_t, ipaddr);
      u16_t port;
    } bc;
    /** 获取IP地址,acpect,会返回我们客户端的IP地址以及端口号*/
    struct {
      ip_addr_t API_MSG_M_DEF(ipaddr);
      u16_t API_MSG_M_DEF(port);
      u8_t local;
    } ad;
    /** write */
    struct {
      const void *dataptr;
      size_t len;
      u8_t apiflags;
#if LWIP_SO_SNDTIMEO
      u32_t time_started;
#endif /* LWIP_SO_SNDTIMEO */
    } w;
    /** read*/
    struct {
      u32_t len;
    } r;
#if LWIP_TCP
    /** 
    	close
    	shutdown
    */
    struct {
      u8_t shut;
#if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
      u32_t time_started;
#else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
      u8_t polls_left;
#endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
    } sd;
#endif /* LWIP_TCP */
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
    /** IGMP */
    struct {
      API_MSG_M_DEF_C(ip_addr_t, multiaddr);
      API_MSG_M_DEF_C(ip_addr_t, netif_addr);
      enum netconn_igmp join_or_leave;
    } jl;
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
// listen(fd, 5)
#if TCP_LISTEN_BACKLOG
    struct {
      u8_t backlog;
    } lb;
#endif /* TCP_LISTEN_BACKLOG */
  } msg;

lwip_netconn接口

#if LWIP_TCP
extern u8_t netconn_aborted;
#endif /* LWIP_TCP */
//当我们自己写socket接口时,最终lwip内核,会针对我们API的类型,进行相关处理,如下所示
void lwip_netconn_do_newconn         (void *m);
void lwip_netconn_do_delconn         (void *m);
void lwip_netconn_do_bind            (void *m);
void lwip_netconn_do_connect         (void *m);
void lwip_netconn_do_disconnect      (void *m);
void lwip_netconn_do_listen          (void *m);
void lwip_netconn_do_send            (void *m);
void lwip_netconn_do_recv            (void *m);
#if TCP_LISTEN_BACKLOG
void lwip_netconn_do_accepted        (void *m);
#endif /* TCP_LISTEN_BACKLOG */
void lwip_netconn_do_write           (void *m);
void lwip_netconn_do_getaddr         (void *m);
void lwip_netconn_do_close           (void *m);
void lwip_netconn_do_shutdown        (void *m);
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
void lwip_netconn_do_join_leave_group(void *m);
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */

#if LWIP_DNS
void lwip_netconn_do_gethostbyname(void *arg);
#endif /* LWIP_DNS */

struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback);
void netconn_free(struct netconn *conn);

netconn_bind

/**
 * @ingroup netconn_common
 * Bind a netconn to a specific local IP address and port.
 * Binding one netconn twice might not always be checked correctly!
 *
 * @param conn the netconn to bind
 * @param addr the local IP address to bind the netconn to 
 *             (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses)
 * @param port the local port to bind the netconn to (not used for RAW)
 * @return ERR_OK if bound, any other err_t on failure
 */
err_t
netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
{

  //api_msg 创建
  API_MSG_VAR_ALLOC(msg);
  //api_msp 赋值
  API_MSG_VAR_REF(msg).conn = conn;
  API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
  API_MSG_VAR_REF(msg).msg.bc.port = port;
  //发送api消息到消息邮箱
  err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
  API_MSG_VAR_FREE(msg);

  return err;
}

netconn_apimsg

/**
 * Call the lower part of a netconn_* function
 * This function is then running in the thread context
 * of tcpip_thread and has exclusive access to lwIP core code.
 *
 * @param fn function to call
 * @param apimsg a struct containing the function to call and its parameters
 * @return ERR_OK if the function was called, another err_t if not
 */
static err_t
netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg)
{
  err_t err;
  //发送消息到消息邮箱,并等待处理完毕后的信号量
  err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg));
  if (err == ERR_OK) {
    return apimsg->err;
  }
  return err;
}

你可能感兴趣的:(lwIP网络,lwip,网络)