一个支持 cgi 的简易 http 服务器

2024-09-01 04:48
文章标签 服务器 http 支持 cgi 简易

本文主要是介绍一个支持 cgi 的简易 http 服务器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自:http://blog.csdn.net/u013904227/article/details/52331438

代码 github 链接:https://github.com/SummerInSun/big-http

1. boa 移植以及使用测试

1. 下载 boa-0.94.14rc21.tar.bz2

http://www.boa.org/news.html

2. 编译安装

  • 解压:tar -xjf boa-0.94.14rc21.tar.bz2
  • 配置:./configure –host=arm-linux –prefix=$PWD/tmp
  • 编译:make
  • 去掉冗余信息:
ls src/boa -l
-rwxr-xr-x 1 book book 233741 2016-08-14 15:34 src/boa
arm-linux-strip src/boa
-rwxr-xr-x 1 book book 72896 2016-08-14 15:37 src/boa

3. 配置

cd examples/
cp boa.conf boa.conf_ok
  • 修改 boa.conf_ok
#  User: The name or UID the server should run as.
# Group: The group name or GID the server should run as.
# 修改为 root 用户,表示 boa 使用 root 用户
User root
Group root# ServerName: the name of this server that should be sent back to 
# clients if different than that returned by gethostname + gethostbyname 
# 去掉注释即可
118 行:ServerName www.your.org.here# DocumentRoot: The root directory of the HTML documents.
# Comment out to disable server non user files.
# 改变为网页存放位置
159 行:DocumentRoot /www# ScriptAlias: Maps a virtual path to a directory for serving scripts
# Example: ScriptAlias /htbin/ /www/htbin/
# 修改 CGI 文件存放的位置
ScriptAlias /cgi-bin/ /www/cgi-bin/
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 开发板:
mkdir -p /var/log/boa    /* 日志文件都存放在这里 */
mkdir /www               /* 网页文件存放在这里 */
mkdir /www/cgi-bin       /* cgi 文件存放的位置 */
mkdir /etc/boa           /* boa.conf 文件放在这里 */cp boa.conf_ok /etc/boa/boa.conf /* 拷贝配置文件 */
cp mime.types /etc/
cp boa /sbin/                    /* 拷贝二进制文件 */
  • 在 www 目录下面编辑 index.html 文件,内容如下
<html>
<head><title>BOA test</title>
</head>
<body>Hellow world!
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 在 /www/cgi-bin 目录下面编辑 cgi-test.c 文件,内容如下
#include <stdio.h>                                            
int  main()                                                   
{                                                                 printf("Content-type: text/html\n\n");                        printf("<html>\n");                                            printf("<head>\n");                                            printf("<title>CGI Output</title>\n");                         printf("</head>\n");                                           printf("<body>");                                             printf("<h1> Hellow, world. </h1>");                           printf("</body>");                                           printf("</html>\n");                                         return 0;                                                    
}
arm-linux-gcc -o cgi-test.cgi cgi-test.c 
  • 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


  • 修改 /etc/init.d/rcS 

添加 /sbin/boa 以开机启动 boa

4. 测试

  • 在本机浏览器里面输入:http://192.168.2.100/cgi-bin/cgi-test.cgi可以看到 Hellow, world. 
    在本机浏览器里面输入:http://192.168.2.100/可以看到 Hellow, world.

2. 自己写 http 服务器

1、tiny-httpd 注释

int main(void)
{初始化一个 socket ,获得套接字描述符,绑定到端口,监听while(1){    // 循环体,接受连接阻塞等待客户端的连接,一旦有连接就获得客户端的地址以及套接字描述符等信息创建线程回应客户端的请求}关闭服务器端口返回
}/**********************************************************************/
/* 相应请求线程                */
/* 处理来自客户端的请求信息    */
/* 参数: 连接的客户端的 socket */
/**********************************************************************/
void accept_request(int client)
{获取第一行发来的数据获取方式 "GET" or "POST"获取请求的资源链接如果是 "GET" 方式的话,获取资源的参数,截断资源链接缓冲区获取资源的完整路径获取资源的文件描述,fstat ,如果失败,说明不存在这个文件如果成功,判断资源文件的属性,是文件夹的话加上 index.html  如果是文件有可执行权限的话就作为 cgi 文件处理,否则的话作为 html 文件处理处理完毕,关闭客户端
}/**********************************************************************/
/* 发送文件到客户端.  如果有错误发生的话就向客户端报告错误* 参数:  客户端 socket 描述符*        文件路径名*/
/**********************************************************************/
void serve_file(int client, const char *filename)
{读取剩下的客户端发来的数据流打开文件返回响应头部信息发送请求的文件关闭文件
}/**********************************************************************/
/* Execute a CGI script.  Will need to set environment variables as* appropriate.* Parameters: client socket descriptor*             path to the CGI script */
/**********************************************************************/
void execute_cgi(int client, const char *path,const char *method, const char *query_string)
{如果是 "GET" 方式,就读取剩下的数据如果是 "POST" 方式,搜寻 "Content-Length:" 字符串获取报文实体的长度发送响应请求的头部信息建立 cgi 输入输出管道fork 本进程,主进程中返回是非0,子进程返回0子进程设置环境变量,执行 cgi 程序主进程接收剩下的  while (read(cgi_output[0], &c, 1) > 0)发送标准输出结果到客户端
}

2. 一个错误

502 Bad Gateway 
The CGI was not CGI/1.1 compliant

  • 错误可能有如下情况:

    1. 文件没有可执行权限
    2. 头部与报文体没有用一个空行隔开
    3. 程序内部某个地方有执行错误
  • 一个 html 文件的请求与回复过程

GET /index.html HTTP/1.1
Host: 192.168.2.100:39681
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2824.2 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8HTTP/1.0 200 OK
Server: jdbhttpd/0.1.0
Content-Type: text/html<HTML>
<TITLE>Index</TITLE>
<BODY>
<P>Welcome to J. David's webserver.
<H1>CGI demo
<FORM ACTION="color.cgi" METHOD="POST">
Enter a color: <INPUT TYPE="text" NAME="color">
<INPUT TYPE="submit">
</FORM>
</BODY>
</HTML>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 一个 cgi 文件的请求与回复过程
POST /color.cgi HTTP/1.1
Host: 192.168.2.100:39681
Connection: keep-alive
Content-Length: 6
Cache-Control: max-age=0
Origin: http://192.168.2.100:39681
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2824.2 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Referer: http://192.168.2.100:39681/index.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.8HTTP/1.0 200 OK
Content-type: text/html<html>
<head>
<title>CGI Output</title>
</head>
<body><h1> Hello, world. </h1></body></html>HTTP/1.1 200 OK
Date: Thu, 01 Jan 1970 04:55:14 GMT
Server: Boa/0.94.14rc21
Accept-Ranges: bytes
Connection: Keep-Alive
Keep-Alive: timeout=10, max=999
Content-Length: 6119
Last-Modified: Thu, 01 Jan 1970 05:01:06 GMT
Content-Type: text/plain
  • 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
  • 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

3. 程序流程:

  • 主程序
int main(int argc, char *argv[])
{格式初始化准备环境:设置用户,当前目录创建服务器 socket fork 主进程,主进程退出,留下子进程往下运行while(1){等待客户端连接若成功,执行响应函数 HandleRequest失败,进入下一轮等待}
}
  • 响应
void HandleRequest(int iClientSocketFd)
{获取客户端的请求头如成功,返回响应报文关闭 iClientSocketFd
}

4. 开发过程中遇到的重要的知识点

  • post 与 get 的区别

    1. http 协议中 
      post:长度没有规定上限。用于修改服务器数据 
      get: 长度没有规定上限。用于获取服务器数据 
      method 与 data 没有关系,两者是相互独立的概念
    2. html 协议中 
      post:约定请求参数放在报文体中,长度随浏览器以及服务器的不同而不同 
      get: 约定请求参数放在 url 或者 cookie 中,长度随浏览器以及服务器的不同而不同。有的服务器接受 get 方式含有 body,但是浏览器不会这样请求 
      两种方式的安全性没有本质的区别,都是可以通过一定方式加密,但是也都可以人为进行截获解密,至于 get 的请求参数放在 url 中可能就比 post 更容易获取吧,后者还要开调试界面
  • send recv 函数

    1. send 
      send 与 write 唯一的区别就是 send 的第四个参数:flag 
      检查 socket 发送缓冲区,如果 buf 大于整个发送缓冲区,返回错误 
      如果 buf 小于发送缓冲区剩余空间长度,就把 buf 内容拷贝到发送缓冲区中 
      如果发送缓冲区剩余空间一直小于 buf 长度,函数会阻塞等待 
      在 send 过程中网络断开会导致进程终止
    2. recv 
      如果 socket 发送缓冲区里面有数据,等待发送缓冲区空 
      如果接收缓冲区空或者正在接收,阻塞等待数据到来 
      在接收过程中网络断开会导致进程终止
  • 服务器 cgi 支持

服务器设置的环境变量:

SERVER_SOFTWARE
SERVER_NAME
GATEWAY_INTERFACE
SERVER_PROTOCOL
SERVER_PORT
REQUEST_METHOD
PATH_INFO
PATH_TRANSLATED
SCRIPT_NAME
QUERY_STRING      /* 重要,对 get 方式来说不可缺少 */
REMOTE_HOST
REMOTE_ADDR
AUTH_TYPE
REMOTE_USER
REMOTE_IDENT
HTTP_COOKIE       /* 浏览器 cookie */
CONTENT_TYPE      /* 重要,对 cgi post 方式不可缺少 */
CONTENT_LENGTH    /* 重要,对 cgi post 方式不可缺少 */


  • putenv 与 setenv 的区别 

putenv 可以使用已有的变量,不给此变量所指向的内容重新分配空间,例: 
char strTmp[256]; 
putenv(strTmp); /* 这里使用的是 strTmp,并没有重新分配空间,如果多次使用 strTmp 会以第一个为准 */ 
也可以为常量字符串分配空间,例: 
putenv(“QUERY_STRING=action=add?name=1”); /* 这里为常量重新分配了空间 */ 
s**etenv 则是每一个环境变量都重新分配一次空间,即使参数不是一个字符串常量也会重新为其分配空间**


  • 在设计编写程序的时候遇到的问题: 


  1. url 请求过长,服务器是否做了限制以及处理
  2. 报文体过长,服务器是否做了限制以及处理
  3. 连接成功建立了,但是浏览器数据发生了延迟或者丢失,服务器是否会永远等待,造成程序死掉
  4. send 数据但是浏览器没有接收到,或者是协议并没有成功发送数据导致缓冲区满,那么下一次 send 就会阻塞等待,而这种等待永远持续下去怎么处理
  5. 在数据发送接收过程中出现断网现象,程序会不会出现卡死或者崩溃

这篇关于一个支持 cgi 的简易 http 服务器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1125990

相关文章

服务器集群同步时间手记

1.时间服务器配置(必须root用户) (1)检查ntp是否安装 [root@node1 桌面]# rpm -qa|grep ntpntp-4.2.6p5-10.el6.centos.x86_64fontpackages-filesystem-1.41-1.1.el6.noarchntpdate-4.2.6p5-10.el6.centos.x86_64 (2)修改ntp配置文件 [r

BUUCTF靶场[web][极客大挑战 2019]Http、[HCTF 2018]admin

目录   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 [web][HCTF 2018]admin 考点:弱密码字典爆破 四种方法:   [web][极客大挑战 2019]Http 考点:Referer协议、UA协议、X-Forwarded-For协议 访问环境 老规矩,我们先查看源代码

Linux服务器Java启动脚本

Linux服务器Java启动脚本 1、初版2、优化版本3、常用脚本仓库 本文章介绍了如何在Linux服务器上执行Java并启动jar包, 通常我们会使用nohup直接启动,但是还是需要手动停止然后再次启动, 那如何更优雅的在服务器上启动jar包呢,让我们一起探讨一下吧。 1、初版 第一个版本是常用的做法,直接使用nohup后台启动jar包, 并将日志输出到当前文件夹n

【Linux】应用层http协议

一、HTTP协议 1.1 简要介绍一下HTTP        我们在网络的应用层中可以自己定义协议,但是,已经有大佬定义了一些现成的,非常好用的应用层协议,供我们直接使用,HTTP(超文本传输协议)就是其中之一。        在互联网世界中,HTTP(超文本传输协议)是一个至关重要的协议,他定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或者传输超文本(比如HTML文档)。

如何确定 Go 语言中 HTTP 连接池的最佳参数?

确定 Go 语言中 HTTP 连接池的最佳参数可以通过以下几种方式: 一、分析应用场景和需求 并发请求量: 确定应用程序在特定时间段内可能同时发起的 HTTP 请求数量。如果并发请求量很高,需要设置较大的连接池参数以满足需求。例如,对于一个高并发的 Web 服务,可能同时有数百个请求在处理,此时需要较大的连接池大小。可以通过压力测试工具模拟高并发场景,观察系统在不同并发请求下的性能表现,从而

速盾:直播 cdn 服务器带宽?

在当今数字化时代,直播已经成为了一种非常流行的娱乐和商业活动形式。为了确保直播的流畅性和高质量,直播平台通常会使用 CDN(Content Delivery Network,内容分发网络)服务器来分发直播流。而 CDN 服务器的带宽则是影响直播质量的一个重要因素。下面我们就来探讨一下速盾视角下的直播 CDN 服务器带宽问题。 一、直播对带宽的需求 高清视频流 直播通常需要传输高清视频

Anaconda 中遇到CondaHTTPError: HTTP 404 NOT FOUND for url的问题及解决办法

最近在跑一个开源项目遇到了以下问题,查了很多资料都大(抄)同(来)小(抄)异(去)的,解决不了根本问题,费了很大的劲终于得以解决,记录如下: 1、问题及过程: (myenv) D:\Workspace\python\XXXXX>conda install python=3.6.13 Solving environment: done.....Proceed ([y]/n)? yDownloa

一种改进的red5集群方案的应用、基于Red5服务器集群负载均衡调度算法研究

转自: 一种改进的red5集群方案的应用: http://wenku.baidu.com/link?url=jYQ1wNwHVBqJ-5XCYq0PRligp6Y5q6BYXyISUsF56My8DP8dc9CZ4pZvpPz1abxJn8fojMrL0IyfmMHStpvkotqC1RWlRMGnzVL1X4IPOa_  基于Red5服务器集群负载均衡调度算法研究 http://ww

RTMP流媒体服务器 crtmpserver

http://www.oschina.net/p/crtmpserver crtmpserver又称rtmpd是Evostream Media Server(www.evostream.com)的社区版本采用GPLV3授权 其主要作用为一个高性能的RTMP流媒体服务器,可以实现直播与点播功能多终端支持功能,在特定情况下是FMS的良好替代品。 支持RTMP的一堆协议(RT

构建高性能WEB之HTTP首部优化

0x00 前言 在讨论浏览器优化之前,首先我们先分析下从客户端发起一个HTTP请求到用户接收到响应之间,都发生了什么?知己知彼,才能百战不殆。这也是作为一个WEB开发者,为什么一定要深入学习TCP/IP等网络知识。 0x01 到底发生什么了? 当用户发起一个HTTP请求时,首先客户端将与服务端之间建立TCP连接,成功建立连接后,服务端将对请求进行处理,并对客户端做出响应,响应内容一般包括响应