mongoose之http调试代码

  1. 使用版本"7.14"

  2. 交互流程图如下:
    在这里插入图片描述

  3. 关键函数

  • mg_mgr_init函数
void mg_mgr_init(struct mg_mgr *mgr) {
  memset(mgr, 0, sizeof(*mgr));
#if MG_ENABLE_EPOLL
  if ((mgr->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
    MG_ERROR(("epoll_create1 errno %d", errno));
#else
  mgr->epoll_fd = -1;
#endif
#if MG_ARCH == MG_ARCH_WIN32 && MG_ENABLE_WINSOCK
  // clang-format off
  { WSADATA data; WSAStartup(MAKEWORD(2, 2), &data); }
  // clang-format on
#elif MG_ENABLE_FREERTOS_TCP
  mgr->ss = FreeRTOS_CreateSocketSet();
#elif defined(__unix) || defined(__unix__) || defined(__APPLE__)
  // Ignore SIGPIPE signal, so if client cancels the request, it
  // won't kill the whole process.
  signal(SIGPIPE, SIG_IGN);
#elif MG_ENABLE_TCPIP_DRIVER_INIT && defined(MG_TCPIP_DRIVER_INIT)
  MG_TCPIP_DRIVER_INIT(mgr);
#endif
  mgr->pipe = MG_INVALID_SOCKET;
  mgr->dnstimeout = 3000;
  mgr->dns4.url = "udp://8.8.8.8:53";
  mgr->dns6.url = "udp://[2001:4860:4860::8888]:53";
  mg_tls_ctx_init(mgr);
}

这是初始化一个mongoose管理结构体,在后面整个程序运行周期中都需要使用。结构体中的struct mg_connection *conns,是链接管理列表,每次有客户端连接都会创建一个id不一样的链接并添加到链接列表中。

  • mg_http_listen函数
struct mg_connection *mg_http_listen(struct mg_mgr *mgr, const char *url,
                                     mg_event_handler_t fn, void *fn_data) {
  struct mg_connection *c = mg_listen(mgr, url, fn, fn_data);
  if (c != NULL) c->pfn = http_cb;
  return c;
}

struct mg_connection *mg_listen(struct mg_mgr *mgr, const char *url,
                                mg_event_handler_t fn, void *fn_data) {
  struct mg_connection *c = NULL;
  if ((c = mg_alloc_conn(mgr)) == NULL) {
    MG_ERROR(("OOM %s", url));
  } else if (!mg_open_listener(c, url)) {
    MG_ERROR(("Failed: %s, errno %d", url, errno));
    MG_PROF_FREE(c);
    free(c);
    c = NULL;
  } else {
    c->is_listening = 1;
    c->is_udp = strncmp(url, "udp:", 4) == 0;
    LIST_ADD_HEAD(struct mg_connection, &mgr->conns, c);
    c->fn = fn;
    c->fn_data = fn_data;
    mg_call(c, MG_EV_OPEN, NULL);
    if (mg_url_is_ssl(url)) c->is_tls = 1;  // Accepted connection must
    MG_DEBUG(("%lu %ld %s", c->id, c->fd, url));
  }
  return c;
}


创建一个监听链接,专门用来监听有没有客户端连接。(这里仅仅只是创建一个链接并添加到链接列表中),c->is_listening = 1。并添加了http协议处理回调函数( c->pfn = http_cb)。这个是接收底层数据后,对底层数据进行解析的回调。并且注册了事件处理函数(c->fn = fn)。对http协议解析后进一步进行处理。

  • mg_mgr_poll函数
  struct mg_connection *c, *tmp;
  uint64_t now;
  printf("i----------------------------\r\n");
  mg_iotest(mgr, ms);
  now = mg_millis();
  mg_timer_poll(&mgr->timers, now);

  for (c = mgr->conns; c != NULL; c = tmp) {
    printf("++++++++++++is_listening %d,is_udp %d\r\n",c->is_listening,c->is_udp);
    bool is_resp = c->is_resp;
    tmp = c->next;
    mg_call(c, MG_EV_POLL, &now);
    if (is_resp && !c->is_resp) {
      printf("====================possible?\r\n");
      long n = 0;
      mg_call(c, MG_EV_READ, &n);
    }
    MG_VERBOSE(("%lu %c%c %c%c%c%c%c %lu %lu", c->id,
                c->is_readable ? 'r' : '-', c->is_writable ? 'w' : '-',
                c->is_tls ? 'T' : 't', c->is_connecting ? 'C' : 'c',
                c->is_tls_hs ? 'H' : 'h', c->is_resolving ? 'R' : 'r',
                c->is_closing ? 'C' : 'c', mg_tls_pending(c), c->rtls.len));
    if (c->is_resolving || c->is_closing) {
      // Do nothing
    } else if (c->is_listening && c->is_udp == 0) {
      if (c->is_readable) accept_conn(mgr, c);
    } else if (c->is_connecting) {
      if (c->is_readable || c->is_writable) connect_conn(c);
      //} else if (c->is_tls_hs) {
      //  if ((c->is_readable || c->is_writable)) mg_tls_handshake(c);
    } else {
      if (c->is_readable) read_conn(c);
      if (c->is_writable) write_conn(c);
    }

    if (c->is_draining && c->send.len == 0) c->is_closing = 1;
    if (c->is_closing) close_conn(c);
  }
}

  1. mg_iotest: 会去监听每个链接,查看链接是否有读的数据,写的数据,或者新的链接。c->is_readable/c->is_writable主要设置这两个变量。
  2. mg_timer_poll: 轮询处理定时器任务处理。
  3. mg_call(c, MG_EV_POLL, &now): 这个用的很妙,比如在发送比较大的文件时,会去调用如static_cb回调函数。每次轮询到此位置时,都会去进入到static_cb函数中,然后填充c->send缓冲区。
  4. mg_call(c, MG_EV_READ, &n): 这个是在数据处理完时,会去读有没有新的http请求进来。如果有继续处理?
  5. write_conn: 发送数据。

下面对个别函数进行分析

  • mg_mkpipe
int mg_mkpipe(struct mg_mgr *mgr, mg_event_handler_t fn, void *fn_data,
              bool udp) {
  union usa usa[2];
  MG_SOCKET_TYPE sp[2] = {MG_INVALID_SOCKET, MG_INVALID_SOCKET};
  struct mg_connection *c = NULL;
  if (!mg_socketpair(sp, usa, udp)) {
    MG_ERROR(("Cannot create socket pair"));
  } else if ((c = mg_wrapfd(mgr, (int) sp[1], fn, fn_data)) == NULL) {
    closesocket(sp[0]);
    closesocket(sp[1]);
    sp[0] = sp[1] = MG_INVALID_SOCKET;
  } else {
    tomgaddr(&usa[0], &c->rem, false);
    MG_DEBUG(("%lu %p pipe %lu", c->id, c->fd, (unsigned long) sp[0]));                                                             
  }
  return (int) sp[0];
}

  1. mg_socketpair 创建两个socket,并且connect上对方。 使用的ip为127.0.0.1,一般sp[1]为服务器端,sp[0] 为客户端。
  2. mg_wrapfd 将sp[1]弄进mg管理列表中
  3. 返回sp[0]客户端socket。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值