[转载] 嵌入式HTTP服务器设计方法

嵌入式HTTP服务器设计方法

为了实现设计目标,嵌入式HTTP服务器一般应采用功能较强的能用PC、工业PC、或高档MPU作为硬件平台,嵌入式实时操作系统作为软件平台进行平发。硬件平台应具备以太网口和一个或多个通信模块,比如RS232、RS485、CAN通信卡等。嵌入式实时操作系统实现了TCP/IP等网络协议,并提供实时任务、进程管理、内存管理、文件系统、API等功能。深圳龙人嵌入式提供全套的嵌入式HTTP服务器设计方案。

一、工作流程

    嵌入式HTTP服务器程序开始运行时,主进程首先创建一个接口,并和主机地址绑定到一起,随后置为被动监听状态,等待客户端连接请求的到来。分别用函数SOCKET()创建一个接口,bind()绑定地址,listen()监听,accept()接收来完成。当建立一个TCP连接后,函数accept()返回一个新的套接口描述符,主进程就创建一个新的子线程(轻质进程)处理这个新的连接。

    子线程用于处理每具体的HTTP请求。子线程首先解析用户的HTTP请求。当用户请求一个网页时,子线程查找文件系统。如果该网页文件存在,且通过权限认证,就把它从CF卡读入内存并扫描,发现有自定义标记则调用相应函数进行处理,最后把结果返回给浏览器;否则给一个简单的出错消息。当用户是上传数据时,子线程调用相应函数读取数据进行处理,并返回处理结果给浏览器。

二、代码设计

    在嵌入式HTTP服务器的代码设计中,考虑到代码的移植性和扩展性,利用C语言实现了面向对象风格的代码结构。代码主要由两上数据结构request_inf和response_inf以及其上一组操作函数组成。结构request_inf和response_inf分别用来保存HTTP请求报文和响应报文的所有信息。在结构定义时,应根据具体应用特点设计结构包含的成分。嵌入式HTTP服务器的函数包括通用函数、CGI函数和自定义标记处理函数等,其中通用函数是一些与HTTP1.1协议有关的函数。

三、通用函数

    void prase_request_line(CHAR *,struct *request_inf)该函数用来解析HTTP请求报文的请求行(Request_Line),并把相应信息存放在结构request_inf中。其中,对请求行中URI部分的解析包括两种情况。如果用户请求一个网页,则获取文件路径、文件类型;如果用户要求上传数据,则把数据放在一个字符数组中。然后将文件路径和类型,或者指向该数组的指针、方法、版本号信息都放入结构request_inf中。

    void prease_general_header(CHAR*,struct*request_inf)该函数用来解析HTTP请求报文的调用首部(General_Header)。之所以把此函数与函数prase_request_line()分开,是考虑到程序的修植性和扩展性。请求行和通用首部是请求报文中的不同部分,不不同的场合下,要求解析的信息可能存在差导师。同时,这样也能使程序结构更清楚。比如,本项目要从通用首部解析字段Keep_Alive。该字段指明一个最长的时间或最大请求数目,在此范围内可以保持TCP连接不被释放。

voidprase_request_header(CHAR*,struct*request_inf)

    void prase_entity_header(CHAR*,struct*request_inf)HTTP请求报文的请求头部用来说明浏览器的一些信息,实体头部则用来说明请求报文中可能存在的实体主体信息。本项目实际上并不需要使用这两个函数来获取相关信息,但考虑到程序的扩展性和移植性,此处仍然把它列出来,它们是两个空函数。

send_status_line(intfd,struct*response_inf)此函数用来产生一个HTTP响应报文的状态行(Status_line)。状态行包括三部分内容,即HTTP版本、状态码以及解释状态码的简单短语。这些信息预先放在结构response_inf中。

send_general_header(intfd,struct*response_inf)

send_response_header(intfd,struct*response_inf)

    send_entity_header(int fd,struct*response_inf)

    这三个函数分别用来产生HTTP响应报文的通用首部、响应首部和实体首部。嵌入式HTTP服务器是一个瘦服务器,功能非常简单。因此HTTP响应报文的通用首部、响应首部和实体首部中的可选字段许多是不需要的,还有许多是固定不变的,例如Last_modified和Content_type字段。Last_modified字段指出资源上次被修改的时间并由接收方解释。如果接收方已有此资源的拷贝,但此拷贝比Last-Modified域所指定的要旧,那该拷贝就是过期的。由于网页文件中含有自定义标记,具有实时性,所以此字段根本没有含有Content_type字段指出实体的媒体类型,本项目中的嵌入式HTTP服务器被设计成只支持HTML类型,因此该字段的内容总是Content_type=text/html。有关服务器和资源的所有标题域信息都被放入结构response_inf中。

send_white_line(intfd)此函数用于实体首部和实体之间传送一个空白行。

    void send_entity_body(int fd,CHAR *buff_file)此函数用来传递实体主体,实体主体实际上是一个处理后的网页文件,它被放在指针buff_file指向的缓冲区内。

voidzero_request_inf(struct*request_inf)

voidzero_response_inf(struct*response_inf)这两个函数用于结构request_inf和response_inf清零。

    void get_file(struct*request_inf,struct * response_inf,CHAR*buff_file,void*,void*)该函数用来处理用户HTTL请求。首先,函数会检查request_inf结构,判断用户是请求一个网页文件还是上传数据。当用户请求网页文件时,函数将根据request_inf结构中的文件路径信息,在文件系统录找此文件。如果文件不存在或不具备权限,则函数将状态码和解释短语写入结构response_inf,然后直接返回;否则读取文件并调用自定义标记处理函数,对标记进行处理,处理过的网页文件被放入buff_file指向的缓冲区内,并把状态码、解释短路和与实体有关的一些信息写入结构response_inf。当用户上传数据时,该函数调用CGI处理函数向CAN总线网络发送帧,然后将状态码和解释短路写入结构response_inf。利用状态码和解释短语只能用“200,OK”或“500,INTERNAL Server ERROR”等,简单反映执行情况。用户要获取详细信息,可待一段合适的时间后请求网页文件。函数中两个void指针分别指向自定义标记处理函数和CGI处理函数,或者对应的函数指针数组。

四、自定义标记处理函数和CGI处理函数

自定义标记处理函数用于对自定义的处理,每一类自定义标记对对应一种自定义标记处理函数,同一类自定义标记的不同数据点利用参数来区分,比如转子秤1的重量标记可以用weight1来表示。所有的自定义标记处理函数被放在一起,构成一个函数指针数组。自定义标记处理函数向CAN总线网络发送远程帧和接收数据帧,获取相应的状态信息。CGI总线网络发送远程帧和接收数据帧,获取相应的状态信息。CGI处理函数用变量名来区分,同一类变量对应一种CGI处理函数。与自定义标记处理函数类似,所有的CGI处理函数也被放在一起,构成一个函数指针数组。

相关推荐