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
,看到的是当前示例程序的目录:
这个时候能看到我们的 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
中的内容了:
下面我们把 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