Mongoose是一个开源web服务器程序,仅有mongoose.c和 mongoose.h两个文件,虽然小巧,但具有基本的web服务器的功能,同时Mongoose是用C编写的,所以很是适合应用到嵌入式设备中。
目前Mongoose能够支持嵌入到C/C++、Python、C#。本文主要介绍下如何在Linux环境下将Mongoose代码嵌入到C应用程序中,并完成服务器的部署工做。
为了更快地熟悉web服务器的特性,在介绍部署服务器以前,有必要先介绍下服务器和客户端之间网络通信的基础传输技术。php
浏览器与Web服务器之间的请求和响应是使用HTTP协议进行的,但HTTP协议只是应用层使用的协议,传输层进行的数据通讯则是经过TCP协议来保证的。
TCP协议是面向链接的协议,整体包括创建链接、数据传输和关闭链接这三个过程,创建链接采用“三次握手”方式来完成,链接成功后便可发送数据,在关闭链接以前,为确保数据正确传递完毕,须要采用“四次挥手”方式关闭链接。下面来分析下“三次握手”和“四次挥手”的过程。html
一、客户端(192.20.1.12)“三次握手”链接服务器(192.20.1.122)程序员
SYN(flag)=1,表示客户端要求创建链接
Seq=x,随机产生序号
SYN(flag)=1
ACK(flag)=1,表示服务器确认请求
ACK(num) =x+1(客户端Seq+1)
Seq=y,随机产生序号
ACK(flag)=1,检查正确,客户端发送确认
ACK(num) =y+1(服务器Seq+1),客户端发送确认号
Seq=x+1
二、客户端(192.20.1.12)与服务器(192.20.1.122)“四次挥手”断开链接。客户端与服务器都可主动发起断开TCP链接请求,此处以客户端发起请求为例。web
FIN(flag)=1,客户端要求终止链接
ACK(num)=z,上包数据Seq值
Seq=x,上包数据ACK(num)值
ACK(flag)=1,表示服务器确认请求
ACK(num) =x+1(客户端Seq+1)
Seq=y,随机产生序号
FIN(flag)=1,服务器要求终止链接
ACK(flag)=1,服务器发送确认
ACK(num) =x+1,与第二次挥手一致
Seq=y,与第二次挥手一致
ACK(flag)=1,检查正确,客户端发送确认
ACK(num) =y+1(服务器Seq+1),客户端发送确认号
Seq=x+1
也许有人会有疑惑,为何创建链接协议是“三次握手”,而关闭链接倒是“四次挥手”呢?因为TCP链接是全双工的,当关闭链接时,服务器收到客户端的FIN报文通知,仅仅表示客户端没有数据发送给服务器,但未必服务器全部的数据都发送给了客户端,可能还须要发送一些数据后再关闭链接。因此ACK报文和FIN报文分开发送造成了“四次挥手”。shell
在网络编程中不可避免地会使用到Socket编程,Socket将TCP/IP协议封装成API接口,
使得程序员更方便地使用TCP/IP协议栈。
Socket是以"打开—读/写—关闭"模式实现,以TCP协议通信的Socket为例,交互流程大体以下,这里从服务器的角度对流程进行介绍:编程
C程序的编译过程当中,依次要进行预处理、编译、汇编、连接四个阶段,在Linux平台shell输入gcc命令完成上述步骤,但gcc在编译一个包含许多源文件的工程时,须要将其中的每一个源文件都编译一遍,而后再所有链接起来,这样效率很是低,尤为当用户只是修改了其中某一个文件的时候,许多已经生成的目标文件是不会改变的,彻底没有必要将每一个文件都从新编译一遍。
为解决gcc编译的低效问题,Windows平台上的集成开发环境(IDE)提供了工程管理器,用户只须要点击一个“make”按钮就能够启动工程管理器对整个程序进行自动编译。
在Linux平台上,make工具和makefile提供了简单有效的工程管理方式。makefile决定编译工程的规则,经过make命令能够启动make工具根据makefile文件中的编译规对程序进行编译和连接,最终生成可执行文件。
Mongoose官网下载的源程序例程中提供了makefile文件,能够直接使用。浏览器
文件一: PROG = simplest_web_server MODULE_CFLAGS=-DMG_DISABLE_DAV_AUTH -DMG_ENABLE_FAKE_DAVLOCK include ../examples.mk 文件二: SUBDIRS = $(sort $(dir $(wildcard ./*/))) SUBDIRS:=$(filter-out ./ ./CC3200/ ./ESP32_IDF/ ./ESP8266_RTOS/ ./mbed/ ./MSP432/ ./nRF51/ ./nRF52/ ./NXP_K64/ ./NXP_LPC4088/ ./PIC32/ ./STM32F4_CC3100/ ./TM4C129/ ./WinCE/, $(SUBDIRS)) ifeq ($(OS), Windows_NT) SUBDIRS:=$(filter-out ./netcat/ ./raspberry_pi_mjpeg_led/ ./captive_dns_server/, $(SUBDIRS)) endif .PHONY: $(SUBDIRS) all: $(SUBDIRS) $(SUBDIRS): @$(MAKE) -C $@ clean: for d in $(SUBDIRS) ; do $(MAKE) -C $$d clean ; done
此处为了更好地说明makefile文件的功能,简单地编写了生成可执行文件的编译规则。将simplest_web_server.c mongoose.h编译成中间文件simplest_web_server.o,mongoose.c mongoose.h编译成中间文件mongoose.o,再将.o文件文件和所需的库文件连接成最终的可执行文件.all服务器
all : simplest_web_server.o mongoose.o gcc -o all simplest_web_server.o mongoose.o simplest_web_server.o : simplest_web_server.c mongoose.h gcc -c simplest_web_server.c mongoose.o : mongoose.c mongoose.h gcc -c mongoose.c
Mongoose开源程序(官网下载6.9版本)提供了多个功能的例程,这里选用simplest_web_server(基础web服务器程序)的main函数做为主应用程序。网络
建立Socket、绑定、监听等流程在如下函数中实现:socket
nc = mg_bind(&mgr, s_http_port, ev_handler);
循环mg_mgr_poll()遍历全部Socket,接受到新链接后进行数据收发,同时调用Socket相应事件处理函数。
for (;;) { mg_mgr_poll(&mgr, 1000); }
由用户实现的事件处理接口以下所示,可在该接口中实现服务器后台的业务逻辑功能:
static void ev_handler(struct mg_connection *nc, int ev, void *p) { if (ev == MG_EV_HTTP_REQUEST) { mg_serve_http(nc, (struct http_message *) p, s_http_server_opts); } }
此处示例在mg_serve_http()中经过Linux文件系统查找index.html文件并返回给浏览器:
if (opts.index_files == NULL) { opts.index_files = "index.html,index.htm,index.shtml,index.cgi,index.php"; }
将mongoose.h、mongoose.c和simplest_web_server.c拷贝到本身的程序目录下,同时将index.html也放置到该目录下。
在Linux的Shell命令行输入make命令,make工具会自动寻找当前目录下的“makefile”文件进行解析,并生成最终的可执行文件.all,运行.all可启动web服务器程序。
在服务器本机的浏览器中输入http://localhost:1200/来访问web服务器,以下图所示:
经过另外一台电脑的浏览器输入http://192.168.20.1:1200/,以下图所示: