【Mongoose笔记】HTTP 服务器

【Mongoose笔记】HTTP 服务器

简介

Mongoose 笔记系列用于记录学习 Mongoose 的一些内容。

Mongoose 是一个 C/C++ 的网络库。它为 TCP、UDP、HTTP、WebSocket、MQTT 实现了事件驱动的、非阻塞的 API。

项目地址:

https://github.com/cesanta/mongoose

学习

下面通过学习 Mongoose 项目代码中的 http-server 示例程序 ,来学习如何使用 Mongoose 实现一个简单的 HTTP 服务器。使用树莓派平台进行开发验证。

http-server 的示例程序不长,代码如下:

// Copyright (c) 2020 Cesanta Software Limited
// All rights reserved

#include 
#include "mongoose.h"

static int s_debug_level = MG_LL_INFO;
static const char *s_root_dir = ".";
static const char *s_listening_address = "http://0.0.0.0:8000";
static const char *s_enable_hexdump = "no";
static const char *s_ssi_pattern = "#.html";

// Handle interrupts, like Ctrl-C
static int s_signo;
static void signal_handler(int signo) {
  s_signo = signo;
}

// Event handler for the listening connection.
// Simply serve static files from `s_root_dir`
static void cb(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
  if (ev == MG_EV_HTTP_MSG) {
    struct mg_http_message *hm = ev_data, tmp = {0};
    struct mg_str unknown = mg_str_n("?", 1), *cl;
    struct mg_http_serve_opts opts = {0};
    opts.root_dir = s_root_dir;
    opts.ssi_pattern = s_ssi_pattern;
    mg_http_serve_dir(c, hm, &opts);
    mg_http_parse((char *) c->send.buf, c->send.len, &tmp);
    cl = mg_http_get_header(&tmp, "Content-Length");
    if (cl == NULL) cl = &unknown;
    MG_INFO(("%.*s %.*s %.*s %.*s", (int) hm->method.len, hm->method.ptr,
             (int) hm->uri.len, hm->uri.ptr, (int) tmp.uri.len, tmp.uri.ptr,
             (int) cl->len, cl->ptr));
  }
  (void) fn_data;
}

static void usage(const char *prog) {
  fprintf(stderr,
          "Mongoose v.%s\n"
          "Usage: %s OPTIONS\n"
          "  -H yes|no - enable traffic hexdump, default: '%s'\n"
          "  -S PAT    - SSI filename pattern, default: '%s'\n"
          "  -d DIR    - directory to serve, default: '%s'\n"
          "  -l ADDR   - listening address, default: '%s'\n"
          "  -v LEVEL  - debug level, from 0 to 4, default: %d\n",
          MG_VERSION, prog, s_enable_hexdump, s_ssi_pattern, s_root_dir,
          s_listening_address, s_debug_level);
  exit(EXIT_FAILURE);
}

int main(int argc, char *argv[]) {
  char path[MG_PATH_MAX] = ".";
  struct mg_mgr mgr;
  struct mg_connection *c;
  int i;

  // Parse command-line flags
  for (i = 1; i < argc; i++) {
    if (strcmp(argv[i], "-d") == 0) {
      s_root_dir = argv[++i];
    } else if (strcmp(argv[i], "-H") == 0) {
      s_enable_hexdump = argv[++i];
    } else if (strcmp(argv[i], "-S") == 0) {
      s_ssi_pattern = argv[++i];
    } else if (strcmp(argv[i], "-l") == 0) {
      s_listening_address = argv[++i];
    } else if (strcmp(argv[i], "-v") == 0) {
      s_debug_level = atoi(argv[++i]);
    } else {
      usage(argv[0]);
    }
  }

  // Root directory must not contain double dots. Make it absolute
  // Do the conversion only if the root dir spec does not contain overrides
  if (strchr(s_root_dir, ',') == NULL) {
    realpath(s_root_dir, path);
    s_root_dir = path;
  }

  // Initialise stuff
  signal(SIGINT, signal_handler);
  signal(SIGTERM, signal_handler);
  mg_log_set(s_debug_level);
  mg_mgr_init(&mgr);
  if ((c = mg_http_listen(&mgr, s_listening_address, cb, &mgr)) == NULL) {
    MG_ERROR(("Cannot listen on %s. Use http://ADDR:PORT or :PORT",
              s_listening_address));
    exit(EXIT_FAILURE);
  }
  if (mg_casecmp(s_enable_hexdump, "yes") == 0) c->is_hexdumping = 1;

  // Start infinite event loop
  MG_INFO(("Mongoose version : v%s", MG_VERSION));
  MG_INFO(("Listening on     : %s", s_listening_address));
  MG_INFO(("Web root         : [%s]", s_root_dir));
  while (s_signo == 0) mg_mgr_poll(&mgr, 1000);
  mg_mgr_free(&mgr);
  MG_INFO(("Exiting on signal %d", s_signo));
  return 0;
}

下面从main函数开始分析代码。

首先是一些变量定义。其中struct mg_mgr是用于保存所有活动连接的事件管理器,struct mg_connection是单个连接描述符。

  char path[MG_PATH_MAX] = ".";
  struct mg_mgr mgr;
  struct mg_connection *c;
  int i;

接下来是解析命令行标志,如下:

  // Parse command-line flags
  for (i = 1; i < argc; i++) {
    if (strcmp(argv[i], "-d") == 0) {
      s_root_dir = argv[++i];
    } else if (strcmp(argv[i], "-H") == 0) {
      s_enable_hexdump = argv[++i];
    } else if (strcmp(argv[i], "-S") == 0) {
      s_ssi_pattern = argv[++i];
    } else if (strcmp(argv[i], "-l") == 0) {
      s_listening_address = argv[++i];
    } else if (strcmp(argv[i], "-v") == 0) {
      s_debug_level = atoi(argv[++i]);
    } else {
      usage(argv[0]);
    }
  }

命令行中有 5 个可以设置的参数,这些可变参数声明为静态变量,默认值如下:

static int s_debug_level = MG_LL_INFO;
static const char *s_root_dir = ".";
static const char *s_listening_address = "http://0.0.0.0:8000";
static const char *s_enable_hexdump = "no";
static const char *s_ssi_pattern = "#.html";

这 5 个参数的含义都写在了 usage 函数中,如果传入的参数标志不对,就会打印出这段说明,介绍可以传入哪些参数及其含义。

static void usage(const char *prog) {
  fprintf(stderr,
          "Mongoose v.%s\n"
          "Usage: %s OPTIONS\n"
          "  -H yes|no - enable traffic hexdump, default: '%s'\n"
          "  -S PAT    - SSI filename pattern, default: '%s'\n"
          "  -d DIR    - directory to serve, default: '%s'\n"
          "  -l ADDR   - listening address, default: '%s'\n"
          "  -v LEVEL  - debug level, from 0 to 4, default: %d\n",
          MG_VERSION, prog, s_enable_hexdump, s_ssi_pattern, s_root_dir,
          s_listening_address, s_debug_level);
  exit(EXIT_FAILURE);
}

接下来是将根目录路径转换成绝对路径。

  // Root directory must not contain double dots. Make it absolute
  // Do the conversion only if the root dir spec does not contain overrides
  if (strchr(s_root_dir, ',') == NULL) {
    realpath(s_root_dir, path);
    s_root_dir = path;
  }

设置 signal 函数捕获 SIGINT 信号和 SIGTERM 信号。

  signal(SIGINT, signal_handler);
  signal(SIGTERM, signal_handler);

下面是对应的信号处理函数,当 SIGINT 信号和 SIGTERM 信号到达时,修改 s_signo 的值,会让主事件循环退出。当用户通过 Ctrl-C 结束进程是会发送 SIGINT 信号,通过 kill 命令不带参数时会发送 SIGTERM 信号。当通过以上两种操作时,都能让主事件循环正常退出。

// Handle interrupts, like Ctrl-C
static int s_signo;
static void signal_handler(int signo) {
  s_signo = signo;
}

设置 Mongoose 日志记录级别,范围 0 - 4, 数值越大日志内容越多。

  mg_log_set(s_debug_level);

初始化一个事件管理器,也就是将最开始定义的struct mg_mgr变量 mgr 中的数据进行初始化。

  mg_mgr_init(&mgr);

通过 mg_http_listen 创建一个监听连接,监听地址s_listening_address,默认为http://0.0.0.0:8000。其中cb是事件处理函数。

  if ((c = mg_http_listen(&mgr, s_listening_address, cb, &mgr)) == NULL) {
    MG_ERROR(("Cannot listen on %s. Use http://ADDR:PORT or :PORT",
              s_listening_address));
    exit(EXIT_FAILURE);
  }

判断 s_enable_hexdump 参数的值,如果把 hexdump 功能开启,则给对应参数进行设置。

  if (mg_casecmp(s_enable_hexdump, "yes") == 0) c->is_hexdumping = 1;

这是事件循环,mg_mgr_poll 遍历所有连接,接受新连接,发送和接收数据,关闭连接,并为各个事件调用事件处理函数。

while (s_signo == 0) mg_mgr_poll(&mgr, 1000);

s_signo 不为 0 时,也就是接收到了退出信号,则结束无限循环,调用 mg_mgr_free 关闭所有连接,释放所有资源。

mg_mgr_free(&mgr);

分析完main函数后,我们看下事件处理函数cb的代码。

判断是否接收到的事件时 HTTP 请求,如果是则开始 HTTP 请求的处理。

if (ev == MG_EV_HTTP_MSG) {

将函数参数ev_data转换为 struct mg_http_message,其中包含已解析的 HTTP 请求。

    struct mg_http_message *hm = ev_data, tmp = {0};

创建 Mongoose 字符串。

    struct mg_str unknown = mg_str_n("?", 1), *cl;

mg_http_serve_dir函数根据 opts 给定的选项提供静态文件,opts.root_dir设置的参数表示 web 根目录,也就是提供的静态文件的目录,opts.ssi_pattern设置的参数表示 SSI 文件名模式。

    struct mg_http_serve_opts opts = {0};
    opts.root_dir = s_root_dir;
    opts.ssi_pattern = s_ssi_pattern;
    mg_http_serve_dir(c, hm, &opts);

将字符串请求解析为mg_http_message结构体的数据tmp

    mg_http_parse((char *) c->send.buf, c->send.len, &tmp);

从上一步得到的tmp中,获取 HTTP header 中 Content-Length 的值。最后将 HTTP 请求中的 method ,URI,HTTP 响应的 URI, Content-Length 的值打印出来。

    cl = mg_http_get_header(&tmp, "Content-Length");
    if (cl == NULL) cl = &unknown;
    MG_INFO(("%.*s %.*s %.*s %.*s", (int) hm->method.len, hm->method.ptr,
             (int) hm->uri.len, hm->uri.ptr, (int) tmp.uri.len, tmp.uri.ptr,
             (int) cl->len, cl->ptr));

http-server 的示例程序代码就都解析完了,下面实际运行一下 http-server 程序。

打开示例程序,编译并运行:

pi@raspberrypi:~ $ cd Desktop/study/mongoose/examples/http-server/
pi@raspberrypi:~/Desktop/study/mongoose/examples/http-server $ make clean all
rm -rf example *.o *.dSYM *.gcov *.gcno *.gcda *.obj *.exe *.ilk *.pdb mongoose mongoose_* mongoose.*
cc ../../mongoose.c main.c -I../.. -I../.. -W -Wall -DMG_ENABLE_LINES=1 -DMG_ENABLE_IPV6=1 -DMG_ENABLE_SSI=1 -DMG_HTTP_DIRLIST_TIME=1  -o example
./example 
1d7e3 2 main.c:96:main                  Mongoose version : v7.8
1d7e3 2 main.c:97:main                  Listening on     : http://0.0.0.0:8000
1d7e3 2 main.c:98:main                  Web root         : [/home/pi/Desktop/study/mongoose/examples/http-server]

这个时候我们的 HTTP 服务器已经运行起来了。

打开浏览器,输入http://localhost:8000,看到的是当前示例程序的目录:

【Mongoose笔记】HTTP 服务器_第1张图片

这个时候能看到我们的 HTTP 服务器打印了如下两行 log :

3c6f4 2 main.c:34:cb                    GET / 200 1948
3c871 2 main.c:34:cb                    GET /favicon.ico 404 0000000010

这些 log 就是在我们的事件处理函数 cb 中打印了,可以看到浏览器向我们的 HTTP 服务器发出了两次 GET 请求,第一次获取/的内容成功,返回状态码 200, 实体主体的大小为 1948;第二次获取网站图标/favicon.ico失败,返回状态码 404,没有找到请求的资源。

接下来我们修改服务器的参数,提高 debug log 的等级,然后重新运行程序,并再从浏览器中去访问:

pi@raspberrypi:~/Desktop/study/mongoose/examples/http-server $ ./example -v 3
11e01a 3 net.c:205:mg_listen            1 0x4 http://0.0.0.0:8000
11e01a 2 main.c:96:main                 Mongoose version : v7.8
11e01a 2 main.c:97:main                 Listening on     : http://0.0.0.0:8000
11e01b 2 main.c:98:main                 Web root         : [/home/pi/Desktop/study/mongoose/examples/http-server]
121ea1 3 sock.c:425:accept_conn         2 0x5 accepted 7f000001.56150 -> 0.8000
121ea2 3 sock.c:425:accept_conn         3 0x6 accepted 7f000001.56154 -> 0.8000
121ead 3 sock.c:281:read_conn           2 0x5 snd 0/0 rcv 0/2048 n=490 err=0
121eae 2 main.c:34:cb                   GET / 200 1948
121eae 3 sock.c:292:write_conn          2 0x5 snd 2033/2048 rcv 0/2048 n=2033 err=2
12206c 3 sock.c:281:read_conn           2 0x5 snd 0/2048 rcv 0/2048 n=431 err=2
12206c 3 http.c:471:mg_http_serve_file  NULL [/home/pi/Desktop/study/mongoose/examples/http-server/favicon.ico]
12206c 2 main.c:34:cb                   GET /favicon.ico 404 0000000010
12206d 3 sock.c:292:write_conn          2 0x5 snd 64/2048 rcv 0/2048 n=64 err=2

可以看到得到的信息更多了。

下面我们修改根目录路径,变为示例程序的上级目录examples,然后重新运行程序,并再从浏览器中去访问:

pi@raspberrypi:~/Desktop/study/mongoose/examples/http-server $ ./example -d ../
1685e8 2 main.c:96:main                 Mongoose version : v7.8
1685e8 2 main.c:97:main                 Listening on     : http://0.0.0.0:8000
1685e8 2 main.c:98:main                 Web root         : [/home/pi/Desktop/study/mongoose/examples]
169c66 2 main.c:34:cb                   GET / 200 7552

打开浏览器看到的内容就变为了上级目录examples中的内容了:

【Mongoose笔记】HTTP 服务器_第2张图片

下面我们把 traffic hexdump 打开,然后重新运行程序,并再从浏览器中去访问:

pi@raspberrypi:~/Desktop/study/mongoose/examples/http-server $ ./example -H yes
16dee 2 main.c:96:main                  Mongoose version : v7.8
16def 2 main.c:97:main                  Listening on     : http://0.0.0.0:8000
16def 2 main.c:98:main                  Web root         : [/home/pi/Desktop/study/mongoose/examples/http-server]
17676 2 sock.c:112:iolog                
-- 2 [0:0:0:0:0:0:0:0]:8000 <- [0:0:0:0:0:0:0:0]:34952  436
0000   47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a   GET / HTTP/1.1..
0010   48 6f 73 74 3a 20 30 2e 30 2e 30 2e 30 3a 38 30   Host: 0.0.0.0:80
0020   30 30 0d 0a 43 6f 6e 6e 65 63 74 69 6f 6e 3a 20   00..Connection: 
0030   6b 65 65 70 2d 61 6c 69 76 65 0d 0a 55 70 67 72   keep-alive..Upgr
0040   61 64 65 2d 49 6e 73 65 63 75 72 65 2d 52 65 71   ade-Insecure-Req
0050   75 65 73 74 73 3a 20 31 0d 0a 55 73 65 72 2d 41   uests: 1..User-A
0060   67 65 6e 74 3a 20 4d 6f 7a 69 6c 6c 61 2f 35 2e   gent: Mozilla/5.
0070   30 20 28 58 31 31 3b 20 4c 69 6e 75 78 20 61 72   0 (X11; Linux ar
0080   6d 76 37 6c 29 20 41 70 70 6c 65 57 65 62 4b 69   mv7l) AppleWebKi
0090   74 2f 35 33 37 2e 33 36 20 28 4b 48 54 4d 4c 2c   t/537.36 (KHTML,
00a0   20 6c 69 6b 65 20 47 65 63 6b 6f 29 20 52 61 73    like Gecko) Ras
00b0   70 62 69 61 6e 20 43 68 72 6f 6d 69 75 6d 2f 37   pbian Chromium/7
00c0   38 2e 30 2e 33 39 30 34 2e 31 30 38 20 43 68 72   8.0.3904.108 Chr
00d0   6f 6d 65 2f 37 38 2e 30 2e 33 39 30 34 2e 31 30   ome/78.0.3904.10
00e0   38 20 53 61 66 61 72 69 2f 35 33 37 2e 33 36 0d   8 Safari/537.36.
00f0   0a 41 63 63 65 70 74 3a 20 74 65 78 74 2f 68 74   .Accept: text/ht
0100   6d 6c 2c 61 70 70 6c 69 63 61 74 69 6f 6e 2f 78   ml,application/x
0110   68 74 6d 6c 2b 78 6d 6c 2c 61 70 70 6c 69 63 61   html+xml,applica
0120   74 69 6f 6e 2f 78 6d 6c 3b 71 3d 30 2e 39 2c 69   tion/xml;q=0.9,i
0130   6d 61 67 65 2f 77 65 62 70 2c 69 6d 61 67 65 2f   mage/webp,image/
0140   61 70 6e 67 2c 2a 2f 2a 3b 71 3d 30 2e 38 2c 61   apng,*/*;q=0.8,a
0150   70 70 6c 69 63 61 74 69 6f 6e 2f 73 69 67 6e 65   pplication/signe
0160   64 2d 65 78 63 68 61 6e 67 65 3b 76 3d 62 33 0d   d-exchange;v=b3.
0170   0a 41 63 63 65 70 74 2d 45 6e 63 6f 64 69 6e 67   .Accept-Encoding
0180   3a 20 67 7a 69 70 2c 20 64 65 66 6c 61 74 65 0d   : gzip, deflate.
0190   0a 41 63 63 65 70 74 2d 4c 61 6e 67 75 61 67 65   .Accept-Language
01a0   3a 20 7a 68 2d 43 4e 2c 7a 68 3b 71 3d 30 2e 39   : zh-CN,zh;q=0.9
01b0   0d 0a 0d 0a                                       ....            
17677 2 main.c:34:cb                    GET / 200 1948
17677 2 sock.c:112:iolog                
-- 2 [0:0:0:0:0:0:0:0]:8000 -> [0:0:0:0:0:0:0:0]:34952  2033
0000   48 54 54 50 2f 31 2e 31 20 32 30 30 20 4f 4b 0d   HTTP/1.1 200 OK.
0010   0a 43 6f 6e 74 65 6e 74 2d 54 79 70 65 3a 20 74   .Content-Type: t
0020   65 78 74 2f 68 74 6d 6c 3b 20 63 68 61 72 73 65   ext/html; charse
0030   74 3d 75 74 66 2d 38 0d 0a 43 6f 6e 74 65 6e 74   t=utf-8..Content
0040   2d 4c 65 6e 67 74 68 3a 20 31 39 34 38 20 20 20   -Length: 1948   
0050   20 0d 0a 0d 0a 3c 21 44 4f 43 54 59 50 45 20 68    ....<!DOCTYPE h
0060   74 6d 6c 3e 3c 68 74 6d 6c 3e 3c 68 65 61 64 3e   tml><html><head>
0070   3c 74 69 74 6c 65 3e 49 6e 64 65 78 20 6f 66 20   <title>Index of 
0080   2f 3c 2f 74 69 74 6c 65 3e 3c 73 63 72 69 70 74   /</title><script
0090   3e 66 75 6e 63 74 69 6f 6e 20 73 72 74 28 74 62   >function srt(tb
00a0   2c 20 73 63 2c 20 73 6f 2c 20 64 29 20 7b 76 61   , sc, so, d) {va
00b0   72 20 74 72 20 3d 20 41 72 72 61 79 2e 70 72 6f   r tr = Array.pro
00c0   74 6f 74 79 70 65 2e 73 6c 69 63 65 2e 63 61 6c   totype.slice.cal
00d0   6c 28 74 62 2e 72 6f 77 73 2c 20 30 29 2c 74 72   l(tb.rows, 0),tr
00e0   20 3d 20 74 72 2e 73 6f 72 74 28 66 75 6e 63 74    = tr.sort(funct
00f0   69 6f 6e 20 28 61 2c 20 62 29 20 7b 20 76 61 72   ion (a, b) { var
0100   20 63 31 20 3d 20 61 2e 63 65 6c 6c 73 5b 73 63    c1 = a.cells[sc
0110   5d 2c 20 63 32 20 3d 20 62 2e 63 65 6c 6c 73 5b   ], c2 = b.cells[
0120   73 63 5d 2c 6e 31 20 3d 20 63 31 2e 67 65 74 41   sc],n1 = c1.getA
0130   74 74 72 69 62 75 74 65 28 27 6e 61 6d 65 27 29   ttribute('name')
0140   2c 20 6e 32 20 3d 20 63 32 2e 67 65 74 41 74 74   , n2 = c2.getAtt
0150   72 69 62 75 74 65 28 27 6e 61 6d 65 27 29 2c 20   ribute('name'), 
0160   74 31 20 3d 20 61 2e 63 65 6c 6c 73 5b 32 5d 2e   t1 = a.cells[2].
0170   67 65 74 41 74 74 72 69 62 75 74 65 28 27 6e 61   getAttribute('na
0180   6d 65 27 29 2c 20 74 32 20 3d 20 62 2e 63 65 6c   me'), t2 = b.cel
0190   6c 73 5b 32 5d 2e 67 65 74 41 74 74 72 69 62 75   ls[2].getAttribu
01a0   74 65 28 27 6e 61 6d 65 27 29 3b 20 72 65 74 75   te('name'); retu
01b0   72 6e 20 73 6f 20 2a 20 28 74 31 20 3c 20 30 20   rn so * (t1 < 0 
01c0   26 26 20 74 32 20 3e 3d 20 30 20 3f 20 2d 31 20   && t2 >= 0 ? -1 
01d0   3a 20 74 32 20 3c 20 30 20 26 26 20 74 31 20 3e   : t2 < 0 && t1 >
01e0   3d 20 30 20 3f 20 31 20 3a 20 6e 31 20 3f 20 70   = 0 ? 1 : n1 ? p
01f0   61 72 73 65 49 6e 74 28 6e 32 29 20 2d 20 70 61   arseInt(n2) - pa
0200   72 73 65 49 6e 74 28 6e 31 29 20 3a 20 63 31 2e   rseInt(n1) : c1.
0210   74 65 78 74 43 6f 6e 74 65 6e 74 2e 74 72 69 6d   textContent.trim
0220   28 29 2e 6c 6f 63 61 6c 65 43 6f 6d 70 61 72 65   ().localeCompare
0230   28 63 32 2e 74 65 78 74 43 6f 6e 74 65 6e 74 2e   (c2.textContent.
0240   74 72 69 6d 28 29 29 29 3b 20 7d 29 3b 66 6f 72   trim())); });for
0250   20 28 76 61 72 20 69 20 3d 20 30 3b 20 69 20 3c    (var i = 0; i <
0260   20 74 72 2e 6c 65 6e 67 74 68 3b 20 69 2b 2b 29    tr.length; i++)
0270   20 74 62 2e 61 70 70 65 6e 64 43 68 69 6c 64 28    tb.appendChild(
0280   74 72 5b 69 5d 29 3b 20 69 66 20 28 21 64 29 20   tr[i]); if (!d) 
0290   77 69 6e 64 6f 77 2e 6c 6f 63 61 74 69 6f 6e 2e   window.location.
02a0   68 61 73 68 20 3d 20 28 27 73 63 3d 27 20 2b 20   hash = ('sc=' + 
02b0   73 63 20 2b 20 27 26 73 6f 3d 27 20 2b 20 73 6f   sc + '&so=' + so
02c0   29 3b 20 7d 3b 77 69 6e 64 6f 77 2e 6f 6e 6c 6f   ); };window.onlo
02d0   61 64 20 3d 20 66 75 6e 63 74 69 6f 6e 28 29 20   ad = function() 
02e0   7b 76 61 72 20 74 62 20 3d 20 64 6f 63 75 6d 65   {var tb = docume
02f0   6e 74 2e 67 65 74 45 6c 65 6d 65 6e 74 42 79 49   nt.getElementByI
0300   64 28 27 74 62 27 29 3b 76 61 72 20 6d 20 3d 20   d('tb');var m = 
0310   2f 73 63 3d 28 5b 30 31 32 5d 29 2e 73 6f 3d 28   /sc=([012]).so=(
0320   31 7c 2d 31 29 2f 2e 65 78 65 63 28 77 69 6e 64   1|-1)/.exec(wind
0330   6f 77 2e 6c 6f 63 61 74 69 6f 6e 2e 68 61 73 68   ow.location.hash
0340   29 20 7c 7c 20 5b 30 2c 20 32 2c 20 31 5d 3b 76   ) || [0, 2, 1];v
0350   61 72 20 73 63 20 3d 20 6d 5b 31 5d 2c 20 73 6f   ar sc = m[1], so
0360   20 3d 20 6d 5b 32 5d 3b 20 64 6f 63 75 6d 65 6e    = m[2]; documen
0370   74 2e 6f 6e 63 6c 69 63 6b 20 3d 20 66 75 6e 63   t.onclick = func
0380   74 69 6f 6e 28 65 76 29 20 7b 20 76 61 72 20 63   tion(ev) { var c
0390   20 3d 20 65 76 2e 74 61 72 67 65 74 2e 72 65 6c    = ev.target.rel
03a0   3b 20 69 66 20 28 63 29 20 7b 69 66 20 28 63 20   ; if (c) {if (c 
03b0   3d 3d 20 73 63 29 20 73 6f 20 2a 3d 20 2d 31 3b   == sc) so *= -1;
03c0   20 73 72 74 28 74 62 2c 20 63 2c 20 73 6f 29 3b    srt(tb, c, so);
03d0   20 73 63 20 3d 20 63 3b 20 65 76 2e 70 72 65 76    sc = c; ev.prev
03e0   65 6e 74 44 65 66 61 75 6c 74 28 29 3b 7d 7d 3b   entDefault();}};
03f0   73 72 74 28 74 62 2c 20 73 63 2c 20 73 6f 2c 20   srt(tb, sc, so, 
0400   74 72 75 65 29 3b 7d 3c 2f 73 63 72 69 70 74 3e   true);}</script>
0410   3c 73 74 79 6c 65 3e 74 68 2c 74 64 20 7b 74 65   <style>th,td {te
0420   78 74 2d 61 6c 69 67 6e 3a 20 6c 65 66 74 3b 20   xt-align: left; 
0430   70 61 64 64 69 6e 67 2d 72 69 67 68 74 3a 20 31   padding-right: 1
0440   65 6d 3b 20 66 6f 6e 74 2d 66 61 6d 69 6c 79 3a   em; font-family:
0450   20 6d 6f 6e 6f 73 70 61 63 65 3b 20 7d 3c 2f 73    monospace; }</s
0460   74 79 6c 65 3e 3c 2f 68 65 61 64 3e 3c 62 6f 64   tyle></head><bod
0470   79 3e 3c 68 31 3e 49 6e 64 65 78 20 6f 66 20 2f   y><h1>Index of /
0480   3c 2f 68 31 3e 3c 74 61 62 6c 65 20 63 65 6c 6c   </h1><table cell
0490   70 61 64 64 69 6e 67 3d 22 30 22 3e 3c 74 68 65   padding="0"><the
04a0   61 64 3e 3c 74 72 3e 3c 74 68 3e 3c 61 20 68 72   ad><tr><th><a hr
04b0   65 66 3d 22 23 22 20 72 65 6c 3d 22 30 22 3e 4e   ef="#" rel="0">N
04c0   61 6d 65 3c 2f 61 3e 3c 2f 74 68 3e 3c 74 68 3e   ame</a></th><th>
04d0   3c 61 20 68 72 65 66 3d 22 23 22 20 72 65 6c 3d   <a href="#" rel=
04e0   22 31 22 3e 4d 6f 64 69 66 69 65 64 3c 2f 61 3e   "1">Modified</a>
04f0   3c 2f 74 68 3e 3c 74 68 3e 3c 61 20 68 72 65 66   </th><th><a href
0500   3d 22 23 22 20 72 65 6c 3d 22 32 22 3e 53 69 7a   ="#" rel="2">Siz
0510   65 3c 2f 61 3e 3c 2f 74 68 3e 3c 2f 74 72 3e 3c   e</a></th></tr><
0520   74 72 3e 3c 74 64 20 63 6f 6c 73 70 61 6e 3d 22   tr><td colspan="
0530   33 22 3e 3c 68 72 3e 3c 2f 74 64 3e 3c 2f 74 72   3"><hr></td></tr
0540   3e 3c 2f 74 68 65 61 64 3e 3c 74 62 6f 64 79 20   ></thead><tbody 
0550   69 64 3d 22 74 62 22 3e 0a 20 20 3c 74 72 3e 3c   id="tb">.  <tr><
0560   74 64 3e 3c 61 20 68 72 65 66 3d 22 2e 2e 22 3e   td><a href="..">
0570   2e 2e 3c 2f 61 3e 3c 2f 74 64 3e 3c 74 64 20 6e   ..</a></td><td n
0580   61 6d 65 3d 2d 31 3e 3c 2f 74 64 3e 3c 74 64 20   ame=-1></td><td 
0590   6e 61 6d 65 3d 2d 31 3e 5b 44 49 52 5d 3c 2f 74   name=-1>[DIR]</t
05a0   64 3e 3c 2f 74 72 3e 0a 20 20 3c 74 72 3e 3c 74   d></tr>.  <tr><t
05b0   64 3e 3c 61 20 68 72 65 66 3d 22 65 78 61 6d 70   d><a href="examp
05c0   6c 65 22 3e 65 78 61 6d 70 6c 65 3c 2f 61 3e 3c   le">example</a><
05d0   2f 74 64 3e 3c 74 64 20 6e 61 6d 65 3d 31 36 36   /td><td name=166
05e0   37 38 33 33 37 35 37 3e 32 30 32 32 2f 31 31 2f   7833757>2022/11/
05f0   30 37 20 32 33 3a 30 39 3a 31 37 3c 2f 74 64 3e   07 23:09:17</td>
0600   3c 74 64 20 6e 61 6d 65 3d 31 34 34 37 30 30 3e   <td name=144700>
0610   31 34 34 37 30 30 3c 2f 74 64 3e 3c 2f 74 72 3e   144700</td></tr>
0620   0a 20 20 3c 74 72 3e 3c 74 64 3e 3c 61 20 68 72   .  <tr><td><a hr
0630   65 66 3d 22 4d 61 6b 65 66 69 6c 65 22 3e 4d 61   ef="Makefile">Ma
0640   6b 65 66 69 6c 65 3c 2f 61 3e 3c 2f 74 64 3e 3c   kefile</a></td><
0650   74 64 20 6e 61 6d 65 3d 31 36 36 37 37 32 38 37   td name=16677287
0660   31 39 3e 32 30 32 32 2f 31 31 2f 30 36 20 31 37   19>2022/11/06 17
0670   3a 35 38 3a 33 39 3c 2f 74 64 3e 3c 74 64 20 6e   :58:39</td><td n
0680   61 6d 65 3d 31 30 35 37 3e 31 30 35 37 3c 2f 74   ame=1057>1057</t
0690   64 3e 3c 2f 74 72 3e 0a 20 20 3c 74 72 3e 3c 74   d></tr>.  <tr><t
06a0   64 3e 3c 61 20 68 72 65 66 3d 22 6d 61 69 6e 2e   d><a href="main.
06b0   63 22 3e 6d 61 69 6e 2e 63 3c 2f 61 3e 3c 2f 74   c">main.c</a></t
06c0   64 3e 3c 74 64 20 6e 61 6d 65 3d 31 36 36 37 37   d><td name=16677
06d0   32 38 37 31 39 3e 32 30 32 32 2f 31 31 2f 30 36   28719>2022/11/06
06e0   20 31 37 3a 35 38 3a 33 39 3c 2f 74 64 3e 3c 74    17:58:39</td><t
06f0   64 20 6e 61 6d 65 3d 33 34 37 34 3e 33 34 37 34   d name=3474>3474
0700   3c 2f 74 64 3e 3c 2f 74 72 3e 0a 20 20 3c 74 72   </td></tr>.  <tr
0710   3e 3c 74 64 3e 3c 61 20 68 72 65 66 3d 22 52 45   ><td><a href="RE
0720   41 44 4d 45 2e 6d 64 22 3e 52 45 41 44 4d 45 2e   ADME.md">README.
0730   6d 64 3c 2f 61 3e 3c 2f 74 64 3e 3c 74 64 20 6e   md</a></td><td n
0740   61 6d 65 3d 31 36 36 37 37 32 38 37 31 39 3e 32   ame=1667728719>2
0750   30 32 32 2f 31 31 2f 30 36 20 31 37 3a 35 38 3a   022/11/06 17:58:
0760   33 39 3c 2f 74 64 3e 3c 74 64 20 6e 61 6d 65 3d   39</td><td name=
0770   36 38 3e 36 38 3c 2f 74 64 3e 3c 2f 74 72 3e 0a   68>68</td></tr>.
0780   3c 2f 74 62 6f 64 79 3e 3c 74 66 6f 6f 74 3e 3c   </tbody><tfoot><
0790   74 72 3e 3c 74 64 20 63 6f 6c 73 70 61 6e 3d 22   tr><td colspan="
07a0   33 22 3e 3c 68 72 3e 3c 2f 74 64 3e 3c 2f 74 72   3"><hr></td></tr
07b0   3e 3c 2f 74 66 6f 6f 74 3e 3c 2f 74 61 62 6c 65   ></tfoot></table
07c0   3e 3c 61 64 64 72 65 73 73 3e 4d 6f 6e 67 6f 6f   ><address>Mongoo
07d0   73 65 20 76 2e 37 2e 38 3c 2f 61 64 64 72 65 73   se v.7.8</addres
07e0   73 3e 3c 2f 62 6f 64 79 3e 3c 2f 68 74 6d 6c 3e   s></body></html>
07f0   0a                                                .               
177cb 2 sock.c:112:iolog                
-- 2 [0:0:0:0:0:0:0:0]:8000 <- [0:0:0:0:0:0:0:0]:34952  369
0000   47 45 54 20 2f 66 61 76 69 63 6f 6e 2e 69 63 6f   GET /favicon.ico
0010   20 48 54 54 50 2f 31 2e 31 0d 0a 48 6f 73 74 3a    HTTP/1.1..Host:
0020   20 30 2e 30 2e 30 2e 30 3a 38 30 30 30 0d 0a 43    0.0.0.0:8000..C
0030   6f 6e 6e 65 63 74 69 6f 6e 3a 20 6b 65 65 70 2d   onnection: keep-
0040   61 6c 69 76 65 0d 0a 55 73 65 72 2d 41 67 65 6e   alive..User-Agen
0050   74 3a 20 4d 6f 7a 69 6c 6c 61 2f 35 2e 30 20 28   t: Mozilla/5.0 (
0060   58 31 31 3b 20 4c 69 6e 75 78 20 61 72 6d 76 37   X11; Linux armv7
0070   6c 29 20 41 70 70 6c 65 57 65 62 4b 69 74 2f 35   l) AppleWebKit/5
0080   33 37 2e 33 36 20 28 4b 48 54 4d 4c 2c 20 6c 69   37.36 (KHTML, li
0090   6b 65 20 47 65 63 6b 6f 29 20 52 61 73 70 62 69   ke Gecko) Raspbi
00a0   61 6e 20 43 68 72 6f 6d 69 75 6d 2f 37 38 2e 30   an Chromium/78.0
00b0   2e 33 39 30 34 2e 31 30 38 20 43 68 72 6f 6d 65   .3904.108 Chrome
00c0   2f 37 38 2e 30 2e 33 39 30 34 2e 31 30 38 20 53   /78.0.3904.108 S
00d0   61 66 61 72 69 2f 35 33 37 2e 33 36 0d 0a 41 63   afari/537.36..Ac
00e0   63 65 70 74 3a 20 69 6d 61 67 65 2f 77 65 62 70   cept: image/webp
00f0   2c 69 6d 61 67 65 2f 61 70 6e 67 2c 69 6d 61 67   ,image/apng,imag
0100   65 2f 2a 2c 2a 2f 2a 3b 71 3d 30 2e 38 0d 0a 52   e/*,*/*;q=0.8..R
0110   65 66 65 72 65 72 3a 20 68 74 74 70 3a 2f 2f 30   eferer: http://0
0120   2e 30 2e 30 2e 30 3a 38 30 30 30 2f 0d 0a 41 63   .0.0.0:8000/..Ac
0130   63 65 70 74 2d 45 6e 63 6f 64 69 6e 67 3a 20 67   cept-Encoding: g
0140   7a 69 70 2c 20 64 65 66 6c 61 74 65 0d 0a 41 63   zip, deflate..Ac
0150   63 65 70 74 2d 4c 61 6e 67 75 61 67 65 3a 20 7a   cept-Language: z
0160   68 2d 43 4e 2c 7a 68 3b 71 3d 30 2e 39 0d 0a 0d   h-CN,zh;q=0.9...
0170   0a                                                .               
177cc 2 main.c:34:cb                    GET /favicon.ico 404 0000000010
177cd 2 sock.c:112:iolog                
-- 2 [0:0:0:0:0:0:0:0]:8000 -> [0:0:0:0:0:0:0:0]:34952  64
0000   48 54 54 50 2f 31 2e 31 20 34 30 34 20 4e 6f 74   HTTP/1.1 404 Not
0010   20 46 6f 75 6e 64 0d 0a 43 6f 6e 74 65 6e 74 2d    Found..Content-
0020   4c 65 6e 67 74 68 3a 20 30 30 30 30 30 30 30 30   Length: 00000000
0030   31 30 0d 0a 0d 0a 4e 6f 74 20 66 6f 75 6e 64 0a   10....Not found.

可以看到把整个 GET 请求和响应的内容都详细的打印了出来。

或者也可以使用 curl 来访问我们的 HTTP 服务器:

pi@raspberrypi:~ $ curl -v http://0.0.0.0:8000/
* Expire in 0 ms for 6 (transfer 0xebc880)
*   Trying 0.0.0.0...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0xebc880)
* Connected to 0.0.0.0 (127.0.0.1) port 8000 (#0)
> GET / HTTP/1.1
> Host: 0.0.0.0:8000
> User-Agent: curl/7.64.0
> Accept: */*
> 
< HTTP/1.1 200 OK
< Content-Type: text/html; charset=utf-8
< Content-Length: 1948    
< 
<!DOCTYPE html><html><head><title>Index of /</title><script>function srt(tb, sc, so, d) {var tr = Array.prototype.slice.call(tb.rows, 0),tr = tr.sort(function (a, b) { var c1 = a.cells[sc], c2 = b.cells[sc],n1 = c1.getAttribute('name'), n2 = c2.getAttribute('name'), t1 = a.cells[2].getAttribute('name'), t2 = b.cells[2].getAttribute('name'); return so * (t1 < 0 && t2 >= 0 ? -1 : t2 < 0 && t1 >= 0 ? 1 : n1 ? parseInt(n2) - parseInt(n1) : c1.textContent.trim().localeCompare(c2.textContent.trim())); });for (var i = 0; i < tr.length; i++) tb.appendChild(tr[i]); if (!d) window.location.hash = ('sc=' + sc + '&so=' + so); };window.onload = function() {var tb = document.getElementById('tb');var m = /sc=([012]).so=(1|-1)/.exec(window.location.hash) || [0, 2, 1];var sc = m[1], so = m[2]; document.onclick = function(ev) { var c = ev.target.rel; if (c) {if (c == sc) so *= -1; srt(tb, c, so); sc = c; ev.preventDefault();}};srt(tb, sc, so, true);}</script><style>th,td {text-align: left; padding-right: 1em; font-family: monospace; }</style></head><body><h1>Index of /</h1><table cellpadding="0"><thead><tr><th><a href="#" rel="0">Name</a></th><th><a href="#" rel="1">Modified</a></th><th><a href="#" rel="2">Size</a></th></tr><tr><td colspan="3"><hr></td></tr></thead><tbody id="tb">
  <tr><td><a href="..">..</a></td><td name=-1></td><td name=-1>[DIR]</td></tr>
  <tr><td><a href="example">example</a></td><td name=1667833757>2022/11/07 23:09:17</td><td name=144700>144700</td></tr>
  <tr><td><a href="Makefile">Makefile</a></td><td name=1667728719>2022/11/06 17:58:39</td><td name=1057>1057</td></tr>
  <tr><td><a href="main.c">main.c</a></td><td name=1667728719>2022/11/06 17:58:39</td><td name=3474>3474</td></tr>
  <tr><td><a href="README.md">README.md</a></td><td name=1667728719>2022/11/06 17:58:39</td><td name=68>68</td></tr>
</tbody><tfoot><tr><td colspan="3"><hr></td></tr></tfoot></table><address>Mongoose v.7.8</address></body></html>
* Connection #0 to host 0.0.0.0 left intact

【参考资料】

examples/http-server


本文链接:https://blog.csdn.net/u012028275/article/details/127823328

你可能感兴趣的:(Mongoose笔记,c语言,c++,网络,http,raspberry,pi)