Linux平台上部署Mongoose服务器的方法介绍

前言

Mongoose是一个开源web服务器程序,仅有mongoose.c和 mongoose.h两个文件,虽然小巧,但具有基本的web服务器的功能,同时Mongoose是用C编写的,所以很是适合应用到嵌入式设备中。
目前Mongoose能够支持嵌入到C/C++、Python、C#。本文主要介绍下如何在Linux环境下将Mongoose代码嵌入到C应用程序中,并完成服务器的部署工做。
为了更快地熟悉web服务器的特性,在介绍部署服务器以前,有必要先介绍下服务器和客户端之间网络通信的基础传输技术。php


TCP链接过程

浏览器与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(num)和ACK(flag)值,并向服务器给出确认
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编程,Socket将TCP/IP协议封装成API接口,
使得程序员更方便地使用TCP/IP协议栈。
Socket是以"打开—读/写—关闭"模式实现,以TCP协议通信的Socket为例,交互流程大体以下,这里从服务器的角度对流程进行介绍:编程

图片描述

  • 建立socket()。socket()根据指定的协议族(IPv4/IPv6)、通讯类型(TCP/UDP)在sockfs文件系统中分配一个使用socket描述字关联的资源,进程能够像访问一个已经打开的文件同样访问socket资源。
  • 绑定bind()。bind()在这个socket上绑定一个指定的端口号和IP地址。网络通讯归根结底可视为不一样计算机上的进程间通信,IP地址只能肯定进程所在的计算机,而结合端口号能够惟一肯定整个网络中的一个网络进程。当IP地址为INADDR_ANY(0)时,表示本地计算机的默认IP地址。
  • 监听listen()。服务器socket端口一直处于等待状态,监听网络中全部客户端对端口号请求,随时准备接收客户端发来的链接
  • 接受accept()。服务器socket监听到客户端请求以后,将请求放在等待队列中,accept()从等待队列中提取链接请求,建立一个新的socket进行操做,而原来所监听的socket不受影响。
  • 读/写write()/read()。发送内容即向socket写入内容,读取内容即从socket获取内容
  • 关闭close()。close()关闭socket。

MakeFile

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

Linux平台运行

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/,以下图所示:

图片描述

相关文章
相关标签/搜索