本篇目标:在之前能ping通pc机的工程基础上搭建web服务器,借鉴官方web服务器的程序与网页,能够用pc机浏览器访问web服务器,并返回设置的网页
材料准备:
-
基础工程:修改后能ping通pc机的工程()
-
搭建工程:最终搭建好的web服务器工程()
-
调试工具:用来调试tcp连接下的数据接收()
-
测试浏览器:这里使用的是Chrome谷歌浏览器
ps:通过修改官方搭建web服务器的代码,来了解搭建的过程,其中暂时去掉了ssi和cgi的程序,仅仅实现网页数据的返回和网页的跳转,并将官方的代码简化到相对最简,以便以后的学习之用
浏览器请求指令探索
要搭建服务器,首先肯定要先了解远程客户端是怎么访问服务器的,这里pc机的浏览器则作为客户端:
-
打开浏览器(谷歌浏览器测试),输入服务器ip;
-
浏览器发送请求命令给服务器;
-
服务器接收到指令后,通过程序来解析指令,找到对应应该返回的网页;
-
服务器发送网页代码给浏览器;
-
浏览器显示网页;
接下来再用搭建虚拟服务器的方法,来模拟一下上面的过程:
-
打开网络调试助手,切换到网络服务器,在服务器操作端口输入80,点击创建,如图;这样我们就创建了一个虚拟的服务器,这个服务器的ip就是pc机的本地ip
-
查看确认一下本地ip地址,可以在网络连接里面查看,也可以在cmd输命令查看,这里的ip地址为192.168.6.104,如图:
-
打开浏览器(谷歌浏览器),输入刚才确认的本地ip地址,这里输入192.168.6.104:
-
返回去看看刚才搭建的服务器有什么变化,会发现有接收到的数据,只要重点观察第一行的数据“GET / HTTP/1.1”,这个字符串将会被服务器解析,然后将网页代码返回回去:
-
找到一个官方程序有一个fs文件夹,里面有已经做好的网页,打开网页index.html,右击-查看源代码,然后全选复制下来,在网络调试助手的发送区粘贴,并点击发送,如图:
-
这时,会发现浏览器已经显示了一张网页,但是好像又有点不全,因为图片没有显示,为什么呢?返回网络调试助手,发现接收区又有好多请求,看字面意思,好像就是图片的请求,然而服务器没有返回图片数据,所以图片无法显示
-
这时候,将所有的浏览器请求列出来比较一下:
“GET / HTTP/1.1”
“GET /STM32F4x7_files/ST.gif HTTP/1.1”
“GET /inchtml-pages-stm32_connectivity_files/pixel.gif HTTP/1.1”
“GET /STM32F4x7_files/stm32.jpg HTTP/1.1”
发现请求中 / 后面一部分的内容不相同,所以服务器只需要解析这一部分的字符串内容,来返回对应的网页数据即可
搭建web服务器
现在创建一个新的c文件,取名为 http_server.c ,接下来写几个函数来建立web服务器,抽重要的函数进行总结一下:
-
web服务器初始化函数 Http_Server_Init():
void Http_Server_Init(void)
{ struct tcp_pcb *http_server_pcb; http_server_pcb = tcp_new(); tcp_bind(http_server_pcb, IP_ADDR_ANY, 80); http_server_pcb = tcp_listen(http_server_pcb); tcp_accept(http_server_pcb, http_server_accept);
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
小结:上面函数主要就是为搭建web服务器做准备,包括申请网络结构体、设置80端口号、监听数据、设置接收数据回调函数;
-
接收数据回调函数 tcp_server_accept() :
static err_t http_server_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{ struct http_state *hs; hs = (struct http_state *)mem_malloc(sizeof(struct http_state)); if (hs != NULL)
{
memset(hs, 0, sizeof(struct http_state));
} tcp_arg(pcb, hs); tcp_recv(pcb, http_server_recv); tcp_poll(pcb, http_server_poll, 4); tcp_sent(pcb, http_sent); return ERR_OK;
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
小结:函数中主要配置一些回调函数,比如接收,轮询,发送;
-
接收数据处理函数 http_server_recv() :
static err_t http_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *http_recv_pbuf, err_t err)
{
err_t parsed = ERR_ABRT;
struct http_state *hs = (struct http_state *)arg; tcp_recved(pcb, http_recv_pbuf->tot_len); if (hs->handle == NULL)
{ parsed = http_parse_request(&http_recv_pbuf, hs, pcb);
} if (parsed != ERR_INPROGRESS)
{ if (hs->req != NULL)
{
pbuf_free(hs->req);
hs->req = NULL;
}
} if (parsed == ERR_OK)
{ http_send_data(pcb, hs);
} else if (parsed == ERR_ARG)
{ close_conn(pcb, hs);
} return ERR_OK;
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
小结:函数主要工作将接收到的数据放入 http_parse_request() 函数进行解析,然后把网页数据发送出去;
-
接收数据解析函数 http_parse_request():
static err_t http_parse_request(struct pbuf **inp, struct http_state *hs, struct tcp_pcb *pcb)
{
char *data;
char *crlf;
u16_t data_len;
struct pbuf *p = *inp;
char *sp1, *sp2;
u16_t uri_len;
char *uri; if (hs->req == NULL)
{
hs->req = p;
} else { pbuf_cat(hs->req, p);
} if (hs->req->next != NULL)
{
data_len = hs->req->tot_len;
pbuf_copy_partial(hs->req, data, data_len, 0);
} else { data = (char *)p->payload;
data_len = p->len;
} if (data_len > 7)
{
crlf = strstr(data, "\r\n"); if (crlf != NULL)
{ if (strncmp(data, "GET ", 4) == 0)
{ sp1 = (data + 4);
} sp2 = strstr(sp1, " "); uri_len = sp2 - (sp1); if ((sp2 != 0) && (sp2 >= (sp1)))
{ uri = sp1; *(sp1 - 1) = 0;
uri[uri_len] = 0;
/* 根据字符串寻找对应网页数据 */
return http_find_file(hs, uri, 0);
}
}
}
return ERR_OK;
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
小结:这个函数是重要的请求数据解析函数,函数将接收到的字符串(例:“GET /STM32F4x7_files/ST.gif HTTP/1.1”)
分离出重要的判断字符串(例:“ /STM32F4x7_files/ST.gif”),然后根据这个字符串的内容来读取对应的网页数据;
-
读取对应网页数据函数 http_find_file():
static err_t http_find_file(struct http_state *hs, const char *uri, int is_09)
{ struct fs_file *file = NULL; if((uri[0] == '/') && (uri[1] == 0))
{
file = fs_open("/index.html");
uri = "/index.html";
} else { file = fs_open(uri);
} return http_init_file(hs, file, is_09, uri);
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
小结:此函数就是网页数据读取函数,里面最重要的函数就是 fs_open() 函数了,这个函数在官方建立web服务器工程里的 fs.c 文件里面,这个函数的解析放到后面;
ps:http_server.c 还有头文件的包含,函数的定义;另外再编写一个http_server.h文件,包含宏定义,结构体定义,函数定义;在下面贴出这两个文件的源码;
上面基本包括了几个重要的函数,当然还有其他的函数,包括发送函数等等,这些函数可以看源代码的注释来理解
文件源码
#include "lwip/debug.h" #include "lwip/stats.h" #include "lwip/tcp.h" #include "http_server.h" #include "fs.h" #include
#include
#include static err_t http_server_accept(void *arg, struct tcp_pcb *pcb, err_t err); static err_t http_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *tcp_recv_pbuf, err_t err); static err_t http_server_poll(void *arg, struct tcp_pcb *pcb); static err_t http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri); static err_t http_find_file(struct http_state *hs, const char *uri, int is_09); static err_t http_parse_request(struct pbuf **inp, struct http_state *hs, struct tcp_pcb *pcb); static u8_t http_send_data(struct tcp_pcb *pcb, struct http_state *hs); static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len); static void close_conn(struct tcp_pcb *pcb, struct http_state *hs); /***
* 函数名称 : Http_Server_Init();
*
* 函数描述 : web服务器初始化;
*
* 传递值 : 无;
*
* 返回值 : 无;
*
**/ void Http_Server_Init(void)
{
struct tcp_pcb *http_server_pcb; http_server_pcb = tcp_new(); tcp_bind(http_server_pcb, IP_ADDR_ANY, 80); http_server_pcb = tcp_listen(http_server_pcb); tcp_accept(http_server_pcb, http_server_accept);
} /***
* 函数名称 : http_server_accept();
*
* 函数描述 : lwip数据接收回调函数,包含对tcp连接的确认,接收回调函数的配置;
*
* 传递值 : *arg, *pcb, err ;
*
* 返回值 : ERR_OK 无错误;
*
**/ static err_t http_server_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct http_state *hs; hs = (struct http_state *)mem_malloc(sizeof(struct http_state)); if (hs != NULL)
{
memset(hs, 0, sizeof(struct http_state));
} tcp_arg(pcb, hs); tcp_recv(pcb, http_server_recv); tcp_poll(pcb, http_server_poll, 4); tcp_sent(pcb, http_sent); return ERR_OK;
} /***
* 函数名称 : http_server_recv();
*
* 函数描述 : 接受到数据后,根据接收到数据的内容,返回网页;
*
* 传递值 : *arg, *pcb, *http_recv_pbuf, err;
*
* 返回值 : ERR_OK无错误;
*
**/ static err_t http_server_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *http_recv_pbuf, err_t err)
{
err_t parsed = ERR_ABRT;
struct http_state *hs = (struct http_state *)arg; tcp_recved(pcb, http_recv_pbuf->tot_len); if (hs->handle == NULL)
{ parsed = http_parse_request(&http_recv_pbuf, hs, pcb);
} if (parsed != ERR_INPROGRESS)
{ if (hs->req != NULL)
{
pbuf_free(hs->req);
hs->req = NULL;
}
} if (parsed == ERR_OK)
{ http_send_data(pcb, hs);
} else if (parsed == ERR_ARG)
{ close_conn(pcb, hs);
} return ERR_OK;
} /***
* 函数名称 : http_server_poll();
*
* 函数描述 : 轮询函数;
*
* 传递值 : *arg, *pcb;
*
* 返回值 : ERR_OK无错误;
*
**/ static err_t http_server_poll(void *arg, struct tcp_pcb *pcb)
{
struct http_state *hs = arg; if (hs == NULL)
{
close_conn(pcb, hs); return ERR_OK;
} else {
hs->retries++; if (hs->retries == 4)
{
close_conn(pcb, hs); return ERR_OK;
} if (hs && (hs->handle))
{ if (http_send_data(pcb, hs))
{
tcp_output(pcb);
}
}
} return ERR_OK;
} /***
* 函数名称 : http_parse_request();
*
* 函数描述 : 对接收到的数据进行解析,根据不同的浏览器请求,返回对应的网页数据;
*
* 传递值 : **inp, *hs, *pcb;
*
* 返回值 : ERR_OK无错误;
*
**/ static err_t http_parse_request(struct pbuf **inp, struct http_state *hs, struct tcp_pcb *pcb)
{ char *data; char *crlf;
u16_t data_len;
struct pbuf *p = *inp; char *sp1, *sp2;
u16_t uri_len; char *uri; if (hs->req == NULL)
{
hs->req = p;
} else { pbuf_cat(hs->req, p);
} if (hs->req->next != NULL)
{
data_len = hs->req->tot_len;
pbuf_copy_partial(hs->req, data, data_len, 0);
} else {
data = (char *)p->payload;
data_len = p->len;
} if (data_len > 7)
{
crlf = strstr(data, "\r\n"); if (crlf != NULL)
{ if (strncmp(data, "GET ", 4) == 0)
{ sp1 = (data + 4);
} sp2 = strstr(sp1, " "); uri_len = sp2 - (sp1); if ((sp2 != 0) && (sp2 >= (sp1)))
{ uri = sp1;
*(sp1 - 1) = 0;
uri[uri_len] = 0; return http_find_file(hs, uri, 0);
}
}
} return ERR_OK;
} /***
* 函数名称 : http_find_file();
*
* 函数描述 : 对提取的数据进行判断,读取对应的网页数据;
*
* 传递值 : *hs, *uri, is_09;
*
* 返回值 : ERR_OK无错误;
*
**/ static err_t http_find_file(struct http_state *hs, const char *uri, int is_09)
{
struct fs_file *file = NULL; if((uri[0] == '/') && (uri[1] == 0))
{
file = fs_open("/index.html");
uri = "/index.html";
} else { file = fs_open(uri);
} return http_init_file(hs, file, is_09, uri);
} /***
* 函数名称 : http_init_file();
*
* 函数描述 : 将要发送的数据保存到http_state结构体当中;
*
* 传递值 : *hs, *file, is_09, *uri;
*
* 返回值 : ERR_OK无错误;
*
**/ static err_t http_init_file(struct http_state *hs, struct fs_file *file, int is_09, const char *uri)
{ if (file != NULL)
{
hs->handle = file; hs->file = (char*)file->data; hs->left = file->len;
hs->retries = 0;
} else {
hs->handle = NULL;
hs->file = NULL;
hs->left = 0;
hs->retries = 0;
} return ERR_OK;
} /***
* 函数名称 : http_send_data();
*
* 函数描述 : 数据发送函数;
*
* 传递值 : *pcb, *hs;
*
* 返回值 : ERR_OK无错误;
*
**/ static u8_t http_send_data(struct tcp_pcb *pcb, struct http_state *hs)
{
err_t err = ERR_OK;
u16_t len;
u8_t data_to_send = 0; if (tcp_sndbuf(pcb) < hs->left)
{
len = tcp_sndbuf(pcb);
} else {
len = (u16_t)hs->left;
} err = tcp_write(pcb, hs->file, len, 1); if (err == ERR_OK)
{
data_to_send = 1;
hs->file += len;
hs->left -= len;
} if ((hs->left == 0) && (fs_bytes_left(hs->handle) <= 0))
{ close_conn(pcb, hs); return 0;
} return data_to_send;
} /***
* 函数名称 : http_sent();
*
* 函数描述 : 数据已经被发送,并且被远程主机确定;
*
* 传递值 : *arg, *pcb, len;
*
* 返回值 : ERR_OK无错误;
*
**/ static err_t http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
struct http_state *hs = (struct http_state *)arg; if (hs == NULL)
{ return ERR_OK;
}
hs->retries = 0;
http_send_data(pcb, hs); return ERR_OK;
} /***
* 函数名称 : close_conn();
* * 函数描述 : 关闭tcp连接;
* * 传递值 : *pcb, *hs;
* * 返回值 : 无;
* **/ static void close_conn(struct tcp_pcb *pcb, struct http_state *hs)
{
tcp_arg(pcb, NULL);
tcp_recv(pcb, NULL);
tcp_err(pcb, NULL);
tcp_poll(pcb, NULL, 0);
tcp_sent(pcb, NULL); if (hs != NULL)
{ if(hs->handle)
{
fs_close(hs->handle);
hs->handle = NULL;
}
mem_free(hs);
}
tcp_close(pcb);
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
-
268
-
269
-
270
-
271
-
272
-
273
-
274
-
275
-
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
-
287
-
288
-
289
-
290
-
291
-
292
-
293
-
294
-
295
-
296
-
297
-
298
-
299
-
300
-
301
-
302
-
303
-
304
-
305
-
306
-
307
-
308
-
309
-
310
-
311
-
312
-
313
-
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
-
322
-
323
-
324
-
325
-
326
-
327
-
328
-
329
-
330
-
331
-
332
-
333
-
334
-
335
-
336
-
337
-
338
-
339
-
340
-
341
-
342
-
343
-
344
-
345
-
346
-
347
-
348
-
349
-
350
-
351
-
352
-
353
-
354
-
355
-
356
-
357
-
358
-
359
-
360
-
361
-
362
-
363
-
364
-
365
-
366
-
367
-
368
-
369
-
370
-
371
-
372
-
373
-
374
-
375
-
376
-
377
-
378
-
379
-
380
-
381
-
382
-
383
-
384
-
385
-
386
-
387
-
388
-
389
-
390
-
391
-
392
-
393
-
394
-
395
-
396
-
397
-
398
-
399
-
400
-
401
-
402
-
403
-
404
-
405
-
406
-
407
-
408
-
409
-
410
-
411
-
412
-
413
-
414
-
415
-
416
-
417
-
418
-
419
-
420
-
421
-
422
-
423
-
424
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
116
-
117
-
118
-
119
-
120
-
121
-
122
-
123
-
124
-
125
-
126
-
127
-
128
-
129
-
130
-
131
-
132
-
133
-
134
-
135
-
136
-
137
-
138
-
139
-
140
-
141
-
142
-
143
-
144
-
145
-
146
-
147
-
148
-
149
-
150
-
151
-
152
-
153
-
154
-
155
-
156
-
157
-
158
-
159
-
160
-
161
-
162
-
163
-
164
-
165
-
166
-
167
-
168
-
169
-
170
-
171
-
172
-
173
-
174
-
175
-
176
-
177
-
178
-
179
-
180
-
181
-
182
-
183
-
184
-
185
-
186
-
187
-
188
-
189
-
190
-
191
-
192
-
193
-
194
-
195
-
196
-
197
-
198
-
199
-
200
-
201
-
202
-
203
-
204
-
205
-
206
-
207
-
208
-
209
-
210
-
211
-
212
-
213
-
214
-
215
-
216
-
217
-
218
-
219
-
220
-
221
-
222
-
223
-
224
-
225
-
226
-
227
-
228
-
229
-
230
-
231
-
232
-
233
-
234
-
235
-
236
-
237
-
238
-
239
-
240
-
241
-
242
-
243
-
244
-
245
-
246
-
247
-
248
-
249
-
250
-
251
-
252
-
253
-
254
-
255
-
256
-
257
-
258
-
259
-
260
-
261
-
262
-
263
-
264
-
265
-
266
-
267
-
268
-
269
-
270
-
271
-
272
-
273
-
274
-
275
-
276
-
277
-
278
-
279
-
280
-
281
-
282
-
283
-
284
-
285
-
286
-
287
-
288
-
289
-
290
-
291
-
292
-
293
-
294
-
295
-
296
-
297
-
298
-
299
-
300
-
301
-
302
-
303
-
304
-
305
-
306
-
307
-
308
-
309
-
310
-
311
-
312
-
313
-
314
-
315
-
316
-
317
-
318
-
319
-
320
-
321
-
322
-
323
-
324
-
325
-
326
-
327
-
328
-
329
-
330
-
331
-
332
-
333
-
334
-
335
-
336
-
337
-
338
-
339
-
340
-
341
-
342
-
343
-
344
-
345
-
346
-
347
-
348
-
349
-
350
-
351
-
352
-
353
-
354
-
355
-
356
-
357
-
358
-
359
-
360
-
361
-
362
-
363
-
364
-
365
-
366
-
367
-
368
-
369
-
370
-
371
-
372
-
373
-
374
-
375
-
376
-
377
-
378
-
379
-
380
-
381
-
382
-
383
-
384
-
385
-
386
-
387
-
388
-
389
-
390
-
391
-
392
-
393
-
394
-
395
-
396
-
397
-
398
-
399
-
400
-
401
-
402
-
403
-
404
-
405
-
406
-
407
-
408
-
409
-
410
-
411
-
412
-
413
-
414
-
415
-
416
-
417
-
418
-
419
-
420
-
421
-
422
-
423
-
424
/* ********************************************************************************************************* * INCLUDE FILES ********************************************************************************************************* */
/* ********************************************************************************************************* * CONSTANTS ********************************************************************************************************* */
/* ********************************************************************************************************* * PERIPH DEFINES ********************************************************************************************************* */
/* ********************************************************************************************************* * DATA TYPES ********************************************************************************************************* */
/* ********************************************************************************************************* * GLOBAL VARIABLES ********************************************************************************************************* */
struct http_state {
struct fs_file *handle;
char *file; /* Pointer to first unsent byte in buf. */ struct pbuf *req; char *buf; /* File read buffer. */
int buf_len; /* Size of file read buffer, buf. */ u32_t left; /* Number of unsent bytes in buf. */
u8_t retries; const char *parsed; /* Pointer to the first unparsed byte in buf. */ const char *tag_started;/* Poitner to the first opening '<' of the tag. */
#endif /* !LWIP_HTTPD_SSI_INCLUDE_TAG */ const char *tag_end; /* Pointer to char after the closing '>' of the tag. */
u32_t parse_left; /* Number of unparsed bytes in buf. */
u16_t tag_index; /* Counter used by tag parsing state machine */
u16_t tag_insert_len; /* Length of insert in string tag_insert */ u16_t tag_part; /* Counter passed to and changed by tag insertion function to insert multiple times */ u8_t tag_check; /* true if we are processing a .shtml file else false */
u8_t tag_name_len; /* Length of the tag name in string tag_name */
char tag_name[LWIP_HTTPD_MAX_TAG_NAME_LEN + 1]; /* Last tag name extracted */
char tag_insert[LWIP_HTTPD_MAX_TAG_INSERT_LEN + 1]; /* Insert string for tag_name */
enum tag_check_state tag_state; /* State of the tag processor */ char *params[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Params extracted from the request URI */
char *param_vals[LWIP_HTTPD_MAX_CGI_PARAMETERS]; /* Values for each extracted param */ const char *hdrs[NUM_FILE_HDR_STRINGS]; /* HTTP headers to be sent. */
u16_t hdr_pos; /* The position of the first unsent header byte in the current string */ u16_t hdr_index; /* The index of the hdr string currently being sent. */ u32_t time_started; u32_t post_content_len_left; u32_t unrecved_bytes;
struct tcp_pcb *pcb;
u8_t no_auto_wnd; };
/* ********************************************************************************************************* * MACRO'S ********************************************************************************************************* */
/* ********************************************************************************************************* * FUNCTION PROTOTYPES ********************************************************************************************************* */
void Http_Server_Init(void);
/* ******************************************************************************************************** * MODULE END ********************************************************************************************************* */
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
-
89
-
90
-
91
-
92
-
93
-
94
-
95
-
96
-
97
-
98
-
99
-
100
-
101
-
102
-
103
-
104
-
105
-
106
-
107
-
108
-
109
-
110
-
111
-
112
-
113
-
114
-
115
官方部分函数解析
读取网页数据文件 fs.c (路径:Project->Standalone->web_server->http):
struct fs_file *fs_open(const char *name)
{
struct fs_file *file;
const struct fsdata_file *f; file = fs_malloc(); if(file == NULL)
{ return NULL;
}
for(f = FS_ROOT; f != NULL; f = f->next)
{ if (!strcmp(name, (char *)f->name))
{
file->data = (const char *)f->data;
file->len = f->len;
file->index = f->len;
file->pextension = NULL;
file->http_header_included = f->http_header_included; return file;
}
}
fs_free(file); return NULL;
}
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
这里关注 f 变量的结构体 fsdata_file,定义在 fsdata.h:
struct fsdata_file
{ const struct fsdata_file *next; const unsigned char *name; const unsigned char *data; int len;
u8_t http_header_included;
};
结构体中有三个重要的变量*next、*name、*data
而在文件fsdata.c中,拉到最后,发现有几个 fsdata_file 的结构体变量,取其中一个来解析一下:
const struct fsdata_file file__index_html[] =
{
{ file__404_html, data__index_html, data__index_html + 12, sizeof(data__index_html) - 12, 1,
}
};
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
变量*name指向的数组前12个数据是字符串 “/index.html” 的ascii码,用于与输入的浏览器请求 “GET /index.html HTTP/1.1” 进行对比;
-
而*data指向数组的12个后的数据,便是网页源代码的16进制数据,这些数据将会由发送函数发送给浏览器,使浏览器显示网页;
web服务器测试
将工程编译后,烧进stm32,将网线与pc机连接:
-
打开浏览器(谷歌浏览器测试)
-
输入服务器ip(这里搭建的服务器ip:192.168.0.10),Enter;
-
浏览器会显示网页,点击网页上的按钮即可以切换不同的网页
如图:
总结:从上面的一系列过程可以get到搭建web服务器的核心思想,然而,现在并没有加入ssi和cgi,所以还无法用网页控制stm32,后面会加上ssi、cgi、post与get请求来完善整个web服务器;
ps:有部分细节的地方解析的不是很清楚,而且自己也没有想明白,需要再加把劲看一些其他的资料来填补空白,共勉~