C++文件服务器项目—FastCGI—4

2023-05-16

C++文件服务器项目—FastCGI—4

  • 前言
  • 1. CGI 概念理解
  • 2. FastCGI 概念理解
  • 3. FastCGI和spawn-fcgi安装
  • 4. FastCGI和 Nginx的关系
  • 5. Nginx数据转发-修改配置文件
  • 6. spawn-fcgi如何启动
  • 7. FastCGI程序怎么写
    • 7.1 echo.c代码阅读与分析
    • 7.2 fastCGI接收与发送数据
    • 7.3 fastCGI程序编写流程与思路
    • 7.4 实现一个fastCGI程序并测试
  • 8. 部署一个能够上传文件的网页
    • 8.1 上传文件夹并修改Nginx的配置文件
    • 8.2 修改配置文件,实现数据转发
    • 8.3 reference & libfcgi.so.0 => not found 问题解决
  • 9. 其他知识点
    • 9.1 HTTP环境变量 -> fastcgi.conf
    • 9.2 常用的四种 Content-Type
  • 10. fastCGI总结

前言

  本文重点介绍FastCGI的概念、如何编写FastCGI程序,以及nginx如何配合fastCGI使用。源码地址:gopherWxf git

  本专栏知识点是通过零声教育的线上课学习,进行梳理总结写下文章,对c/c++linux课程感兴趣的读者,可以点击链接 C/C++后台高级服务器课程介绍 详细查看课程的服务。

1. CGI 概念理解

  CGI:通用网关接口Common Gateway Interface/CGI描述了客户端和服务器程序之间传输数据的一种标准,可以让一个客户端,从网页浏览器向执行在网络服务器上的程序请求数据。CGI 独立于任何语言的,CGI 程序可以用任何脚本语言或者是完全独立编程语言实现,只要这个语言可以在这个系统上运行

在这里插入图片描述

http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man

  比如上面这个url请求,web nginx server是能够解析的,但是它不能处理,因为这里带了数据,是动态请求,而nginx只能处理静态请求。所以要把动态请求交给CGI去处理。

在这里插入图片描述

http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man

  1. 用户通过浏览器访问服务器, 发送了一个请求, 请求的url如上
  2. 服务器接收数据, 对接收的数据进行解析
  3. nginx对于一些登录数据不知道如何处理, nginx将数据发送给了cgi程序
    • 服务器端会创建一个CGI进程
  4. CGI进程执行
    • 加载配置, 如果有需求加载配置文件获取数据
    • 连接其他服务器: 比如数据库
    • 逻辑处理:
    • 得到处理结果, 将结果发送给服务器
    • 退出
  5. 服务器将cgi处理结果发送给客户端
    • 每一个动态资源请求都有一个CGI进程
    • 在服务器端CGI进程会被频繁的创建销毁
    • 频繁的创建销毁CGI进程,服务器开销大, 效率低

2. FastCGI 概念理解

  fastCGI:快速通用网关接口(Fast Common Gateway Interface/FastCGI)是通用网关接口(CGI)的改进,描述了客户端和服务器程序之间传输数据的一种标准。FastCGI致力于减少Web服务器CGI程式之间互动的开销,从而使服务器可以同时处理更多的Web请求。与为每个请求创建一个新的进程不同,FastCGI使用持续的进程来处理一连串的请求。这些进程由FastCGI进程管理器管理,而不是web服务器。

fastCGI与CGI的区别: CGI 就是所谓的短生存期应用程序,FastCGI 就是所谓的长生存期应用程序。FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,不会每次都要花费时间去fork一次。说人话:CGI是来一个请求就fork一个进程,而fastCGI只会fork一个进程,多个请求都使用同一个进程。

在这里插入图片描述

http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man

  1. 用户通过浏览器访问服务器, 发送了一个请求, 请求的url如上
  2. 服务器接收数据, 对接收的数据进行解析
  3. nginx对于一些登录数据不知道如何处理, nginx将数据发送给了fastcgi程序
    • 通过本地套接字
    • 网络通信的方式
  4. fastCGI程序如何启动
    • 不是由web服务器直接启动
    • 通过一个fastCGI进程管理器启动
  5. fastcgi启动
    • 加载配置 - 可选
    • 连接服务器 - 数据库
    • 循环
      • 服务器有请求 -> 处理
      • 没有请求 -> 阻塞等待
  6. 服务器将fastCGI的处理结果发送给客户端
    • 通过本地套接字
    • 网络通信的方式

3. FastCGI和spawn-fcgi安装

  fastCGI是一个框架,它给我们提供了api,它内部遵循cgi协议,以及与服务器通信的细节隐藏了。我们只需要遵循fastCGI的api接口去写程序,就可以与nginx配合使用了。

  spawn-fcgi是FastCGI的进程管理器,也就是说我们编写的FastCGI程序,是由spawn-fcgi去启动,而不是由nginx web服务器去启动。

  spawn-fcgi-1.6.4.tar.gzfcgi-2.4.1-SNAP-0910052249.tar.gz都在前言的git源码处,需要的可以进git hub下载。

  1. 安装fastCGI
tar zxvf fcgi-2.4.1-SNAP-0910052249.tar.gz 
cd fcgi-2.4.1-SNAP-0910052249/
./configure
make
make install
ldconfig
make
# make的时候如果出现EOF的错误,是因为这个cpp文件没有添加头文件
- fcgio.cpp:50:14: error: 'EOF' was not declared in this scope
- 没有包含对应的头文件:
	- stdio.h - c
	- cstdio -> c++
vi ./libfcgi/fcgio.cpp
#include<cstdio>
  1. 安装spawn-fcgi
tar -zxvf spawn-fcgi-1.6.4.tar.gz 
cd spawn-fcgi-1.6.4/
./configure 
make
make install
ldconfig

4. FastCGI和 Nginx的关系

  nginx 不能像apache那样直接执行外部可执行程序,但nginx可以作为代理服务器,将请求转发给后端服务器,这也是nginx的主要作用之一。其中nginx就支持FastCGI代理,接收客户端的请求,然后将请求转发给后端fastcgi进程。后文会介绍如何使用C/C++编写cgi/fastcgi,并部署到nginx中。

  通过前面的介绍知道,fastcgi进程由FastCGI进程管理器管理,而不是nginx。这样就需要一个FastCGI管理,管理我们编写fastcgi程序。我们使用spawn-fcgi作为FastCGI进程管理器。

  spawn-fcgi是一个通用的FastCGI进程管理器,简单小巧,原先是属于lighttpd的一部分,后来由于使用比较广泛,所以就迁移出来作为独立项目了。spawn-fcgi使用pre-fork 模型,功能主要是打开监听端口,绑定地址,然后fork-and-exec创建我们编写的fastcgi应用程序进程,退出完成工作。fastcgi应用程序初始化,然后进入死循环侦听socket的连接请求。

在这里插入图片描述

http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man

  • 客户端访问, 发送请求
  • nginx web服务器, 无法处理用户提交的数据,将数据转发给 spawn-fcgi
  • spawn-fcgi - 通信过程中的服务器角色
    • 被动接收数据
    • 在spawn-fcgi启动的时候给其绑定IP和端口
  • fastCGI程序
    • 程序猿写的 -> login.c -> 可执行程序login
    • 使用 spawn-fcgi 进程管理器启动 login 程序, 得到一进程
      • login进程处理请求数据
      • 处理完后数据发送给nginx
      • 阻塞等待下一个请求的到来

5. Nginx数据转发-修改配置文件

  nginx的数据转发,需要修改nginx的配置文件 nginx.conf(/usr/local/nginx/conf)

通过请求的url http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man 转换为一个指令:
	- 去掉协议
	- 去掉域名/IP + 端口
	- 如果尾部有文件名 去掉
	- 去掉 ? + 后边的字符串
	- 剩下的就是服务器要处理的指令: /login
location /login
{
    # 转发这个数据, fastCGI进程
    fastcgi_pass 地址信息:端口;
    # fastcgi.conf 和nginx.conf在同一级目录: /usr/local/nginx/conf
    # 这个文件中定义了一些http通信的时候用到环境变量, nginx赋值的
    include fastcgi.conf;
}
地址信息: 
	- localhost
	- 127.0.0.1
	- 192.168.1.100
端口: 找一个空闲的没有被占用的端口即可

6. spawn-fcgi如何启动

# 前提条件: 程序猿的fastCGI程序已经编写完毕 -> 可执行文件 login
spawn-fcgi -a IP地址 -p 端口 -f ./fastcgi可执行程序login
 - IP地址: 应该和nginx的 fastcgi_pass 配置项对应
 	- nginx: localhost       ->   IP: 127.0.0.1
	- nginx: 127.0.0.1	     ->   IP: 127.0.0.1
	- nginx: 192.168.109.101 ->   IP: 192.168.109.101
- 端口:
	应该和nginx的 fastcgi_pass 中的端口一致

7. FastCGI程序怎么写

7.1 echo.c代码阅读与分析

  进入FastCGI源码目录下的example目录,看echo.c是如何编写的

root@wxf:/source_code_dir/fcgi-2.4.1-SNAP-0910052249/examples# pwd
/source_code_dir/fcgi-2.4.1-SNAP-0910052249/examples
root@wxf:/source_code_dir/fcgi-2.4.1-SNAP-0910052249/examples# ls
authorizer      echo.c        echo.mak   echo-x.o    Makefile.am  size.o
authorizer.c    echo-cpp      echo.o     log-dump    Makefile.in  threaded
authorizer.mak  echo-cpp.cpp  echo-x     log-dump.c  size         threaded.c
authorizer.o    echo-cpp.mak  echo-x.c   log-dump.o  size.c       threaded-threaded.o
echo            echo-cpp.o    echox.mak  Makefile    size.mak

  • echo.c
#ifndef lint
static const char rcsid[] = "$Id: echo.c,v 1.5 1999/07/28 00:29:37 roberts Exp $";
#endif /* not lint */

#include "fcgi_config.h"
#include <stdlib.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#ifdef _WIN32
#include <process.h>
#else
extern char **environ;
#endif

#include "fcgi_stdio.h"

static void PrintEnv(char *label, char **envp) {
    printf("%s:<br>\n<pre>\n", label);
    for (; *envp != NULL; envp++) {
        printf("%s\n", *envp);
    }
    printf("</pre><p>\n");
}

int main() {
    char **initialEnv = environ;
    int count = 0;

    while (FCGI_Accept() >= 0) {
        char *contentLength = getenv("CONTENT_LENGTH");
        int len;

        printf("Content-type: text/html\r\n"
               "\r\n"
               "<title>FastCGI echo</title>"
               "<h1>FastCGI echo</h1>\n"
               "Request number %d,  Process ID: %d<p>\n", ++count, getpid());

        if (contentLength != NULL) {
            len = strtol(contentLength, NULL, 10);
        }
        else {
            len = 0;
        }

        if (len <= 0) {
            printf("No data from standard input.<p>\n");
        }
        else {
            int i, ch;

            printf("Standard input:<br>\n<pre>\n");
            for (i = 0; i < len; i++) {
                if ((ch = getchar()) < 0) {
                    printf("Error: Not enough bytes received on standard input<p>\n");
                    break;
                }
                putchar(ch);
            }
            printf("\n</pre><p>\n");
        }

        PrintEnv("Request environment", environ);
        PrintEnv("Initial environment", initialEnv);
    } /* while */

    return 0;
}

  char **environ是一个全局变量,在#include <unistd.h>中,它其实就是存储了linux bash中输入env打印出来的环境变量。所以PrintEnv这个函数就是把所有的键值对打印出来。

在这里插入图片描述

  程序显示往标准输出里面打印了这个kv

printf("Content-type: text/html\r\n");

  while (FCGI_Accept() >= 0)符合上文的分析,如果有请求来了那么就会进入循环。

  通过环境变量,获取http请求报文头中这个字段的值。CONTENT_LENGTH其实就在fastcgi.conf中,在上文修改配置文件的时候,被include了。

char *contentLength = getenv("CONTENT_LENGTH");

  然后从标准输入读这个长度的数据,再写入标准输出。

for (i = 0; i < len; i++) {
    if ((ch = getchar()) < 0) {
        printf("Error: Not enough bytes received on standard input<p>\n");
        break;
    }
    putchar(ch);
}

7.2 fastCGI接收与发送数据

  从上文我们发现,该程序从标准输入读数据,往标准输出写数据。很明显,这里是做了重定向的。表面操作的是终端,实际被重定向到了内部被隐藏的fd。

dup2(fd,STDIN_FILENO)
dup2(fd,STDOUT_FILENO)

7.3 fastCGI程序编写流程与思路

// http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man
// 要包含的头文件
#include "fcgi_config.h" // 可选
#include "fcgi_stdio.h" // 必须的, 编译的时候找不到这个头文件, find->path , gcc -I
// 编写代码的流程
int main()
{
    // FCGI_Accept()是一个阻塞函数, nginx给fastcgi程序发送数据的时候解除阻塞
    while (FCGI_Accept() >= 0) 
    {
        // 1. 接收数据
        	// 1.1 get方式提交数据 - 数据在请求行的第二部分,QUERY_STRING直接获取数据
        	// user=zhang3&passwd=123456&age=12&sex=man
        	char *text = getenv("QUERY_STRING"); 
        	
        	// 1.2 post方式提交数据,只能获取数据长度,需要手动读出来
        	char *contentLength = getenv("CONTENT_LENGTH");
        	// 根据长度大小判断是否需要循环读-read
        
        // 2. 按照业务流程进行处理
        ...
        ...
        // 3. 将处理结果发送给nginx
        	// 3.1 数据回发的时候, 需要告诉nginx处理结果的格式 - 假设是html格式。只有Content-type需要指定,别的头部字段自动,不用我们管
        	// 要放在处理结果之前发送该kv字段
        	//Content-type后续会介绍
        	printf("Content-type: text/html\r\n");
		
			// 注意\r\n ,别忘了空行!
			printf("\r\n");

        	// 3.2 再将处理结果回发
        	printf("<html>处理结果</html>");
    }
}

7.4 实现一个fastCGI程序并测试

  • 第一步:修改Nginx数据转发的配置文件
    location /upload/UploadAction {
        fastcgi_pass 192.168.109.101:10000;
        include fastcgi.conf;
    }
  • 第二步:编写fastCGI程序
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fcgi_stdio.h"

int main(int argc, char *argv[]) {
    int count = 0;
    while (FCGI_Accept() >= 0) {
        printf("Content-type: text/html\r\n");
        
        printf("\r\n");

        printf("<title>Fast CGI Hello WXF!</title>");
        printf("<h1>Fast CGI Hello WXF!</h1>");
        printf("Request number %d running on host <i>%s</i>\n", ++count, getenv("SERVER_NAME"));
    }
    return 0;
}
  • 第三步:启动fastcgi进程管理器
root@wxf:/source_code_dir# gcc -o test fcgi.c -lfcgi
root@wxf:/source_code_dir# spawn-fcgi -a 192.168.109.101 -p 10000 -f ./test 
spawn-fcgi: child spawned successfully: PID: 14487
  • 第四步:测试

在这里插入图片描述

8. 部署一个能够上传文件的网页

8.1 上传文件夹并修改Nginx的配置文件

  至于为什么放在/usr/local/nginx/目录下不再赘述,不懂的读者可以翻阅我上一篇nginx的文章。

在这里插入图片描述

location / {
    root   zyFile2;
    index  index.html index.htm;
}

在这里插入图片描述
在这里插入图片描述

8.2 修改配置文件,实现数据转发

在这里插入图片描述

  为什么是404 Not Found?通过html的源码,我们发现发送的是post请求,并且路径是/upload/UploadAction。这意味着带数据的动态请求,nginx是处理不了的,所以这个时候我们需要配置数据转发。

在这里插入图片描述

location /upload/UploadAction {
    fastcgi_pass 192.168.109.101:10000;
    include fastcgi.conf;
}

在这里插入图片描述
  An error occurred是因为虽然我们配置了数据转发,但是我们并没有启动fastcgi程序去处理这个请求。

在这里插入图片描述

  现在我们使用之前介绍过的echo.c当作fastcgi程序,实现回发的功能看看。

root@wxf:/source_code_dir# gcc -o echo echo.c -lfcgi
root@wxf:/source_code_dir# spawn-fcgi -a 192.168.109.101 -p 10000 -f ./echo
spawn-fcgi: child spawned successfully: PID: 14762

  注意这里不要上传太大的图片,因为我们回发的类型是Content-type: text/html,并不符合图片的类型。可以看到这里我们上传的流程成功了,我们并没有编写上传的代码,只是做了个echo而已。

在这里插入图片描述

8.3 reference & libfcgi.so.0 => not found 问题解决

没有对应的动态库,那么加上即可

root@wxf:/source_code_dir# gcc -o echo echo.c
/tmp/ccghTkS5.o: In function `PrintEnv':
echo.c:(.text+0x24): undefined reference to `FCGI_printf'
echo.c:(.text+0x41): undefined reference to `FCGI_printf'
echo.c:(.text+0x63): undefined reference to `FCGI_printf'
/tmp/ccghTkS5.o: In function `main':
echo.c:(.text+0xb6): undefined reference to `FCGI_printf'
echo.c:(.text+0xf6): undefined reference to `FCGI_printf'
/tmp/ccghTkS5.o:echo.c:(.text+0x109): more undefined references to `FCGI_printf' follow
/tmp/ccghTkS5.o: In function `main':
echo.c:(.text+0x117): undefined reference to `FCGI_getchar'
echo.c:(.text+0x131): undefined reference to `FCGI_printf'
echo.c:(.text+0x13d): undefined reference to `FCGI_putchar'
echo.c:(.text+0x15a): undefined reference to `FCGI_printf'
echo.c:(.text+0x188): undefined reference to `FCGI_Accept'
collect2: error: ld returned 1 exit status
root@wxf:/source_code_dir# cd fcgi-2.4.1-SNAP-0910052249/
root@wxf:/source_code_dir/fcgi-2.4.1-SNAP-0910052249# find ./ -name "lib*.so"
./libfcgi/.libs/libfcgi++.so
./libfcgi/.libs/libfcgi.so
root@wxf:/source_code_dir/fcgi-2.4.1-SNAP-0910052249# cd ..
root@wxf:/source_code_dir# gcc -o echo echo.c -lfcgi

    ldd echo查看程序启动之后需要加载的动态库,如果发现not found,那么就有问题了。

在这里插入图片描述
  使用find查找这个动态库的位置

root@wxf:/source_code_dir# find / -name "libfcgi.so"
/usr/local/lib/libfcgi.so
/source_code_dir/fcgi-2.4.1-SNAP-0910052249/libfcgi/.libs/libfcgi.so

  我们需要让程序能够连接到这个动态库,就把这个/usr/local/lib这个目录放到下面的配置文件,并用ldconfig更新。

root@wxf:/source_code_dir# vi /etc/ld.so.conf
...
root@wxf:/source_code_dir# ldconfig

  上述问题发生的原因是因为,手动安装这些源码make install之后,没有输入ldconfig导致的。

9. 其他知识点

9.1 HTTP环境变量 -> fastcgi.conf

  上文测试的echo程序回发了两个环境变量,Request environmentInitial environment。分别是HTTP请求的环境变量和fastcgi系统的环境变量。

  Request environment中的环境变量都在fastcgi.conf中记录着。

  Initial environment中的环境变量都在bash: env 打印出来的一样。

Request number 2, Process ID: 14762
Standard input:
------WebKitFormBoundaryM3hhJcyUYWxGGdPb
Content-Disposition: form-data; name="file"; filename="100k.png"
Content-Type: image/png

�PNG


IHDRdN)IDAT8c���?Y��,] M�:	�h��$FS�hJ�)�5��IEND�B`�
------WebKitFormBoundaryM3hhJcyUYWxGGdPb
Content-Disposition: form-data; name="tailor"

false
------WebKitFormBoundaryM3hhJcyUYWxGGdPb--

Request environment:
FCGI_ROLE=RESPONDER
SCRIPT_FILENAME=/usr/local/nginx/html/upload/UploadAction
QUERY_STRING=
REQUEST_METHOD=POST
CONTENT_TYPE=multipart/form-data; boundary=----WebKitFormBoundaryM3hhJcyUYWxGGdPb
CONTENT_LENGTH=377
SCRIPT_NAME=/upload/UploadAction
REQUEST_URI=/upload/UploadAction
DOCUMENT_URI=/upload/UploadAction
DOCUMENT_ROOT=/usr/local/nginx/html
SERVER_PROTOCOL=HTTP/1.1
REQUEST_SCHEME=http
GATEWAY_INTERFACE=CGI/1.1
SERVER_SOFTWARE=nginx/1.16.1
REMOTE_ADDR=192.168.109.1
REMOTE_PORT=55644
SERVER_ADDR=192.168.109.101
SERVER_PORT=80
SERVER_NAME=localhost
REDIRECT_STATUS=200
HTTP_HOST=192.168.109.101
HTTP_CONNECTION=keep-alive
HTTP_CONTENT_LENGTH=377
HTTP_USER_AGENT=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36
HTTP_CONTENT_TYPE=multipart/form-data; boundary=----WebKitFormBoundaryM3hhJcyUYWxGGdPb
HTTP_ACCEPT=*/*
HTTP_ORIGIN=http://192.168.109.101
HTTP_REFERER=http://192.168.109.101/demo.html
HTTP_ACCEPT_ENCODING=gzip, deflate
HTTP_ACCEPT_LANGUAGE=zh-CN,zh;q=0.9
Initial environment:
LESSOPEN=| /usr/bin/lesspipe %s
MAIL=/var/mail/root
USER=root
SSH_CLIENT=192.168.109.1 61011 22
SHLVL=1
OLDPWD=/usr/local/nginx/conf
HOME=/root
SSH_TTY=/dev/pts/0
DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/0/bus
LOGNAME=root
_=/usr/local/bin/spawn-fcgi
XDG_SESSION_ID=1
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
XDG_RUNTIME_DIR=/run/user/0
DISPLAY=localhost:10.0
LANG=en_US.UTF-8
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:
SHELL=/bin/bash
LESSCLOSE=/usr/bin/lesspipe %s %s
PWD=/source_code_dir
SSH_CONNECTION=192.168.109.1 61011 192.168.109.101 22
XDG_DATA_DIRS=/usr/local/share:/usr/share:/var/lib/snapd/desktop

  最重要的就是下面四个。如果是get请求,则不会有CONTENT_LENGTH字段,参数在QUERY_STRING中。如果是post请求,则有CONTENT_LENGTH字段。

QUERY_STRING
REQUEST_METHOD
CONTENT_TYPE
CONTENT_LENGTH

在这里插入图片描述

  • fastCGI环境变量 - fastcgi.conf

    环境变量说明
    SCRIPT_FILENAME脚本文件请求的路径
    QUERY_STRING请求的参数;如?app=123
    REQUEST_METHOD请求的动作(GET,POST)
    CONTENT_TYPE请求头中的Content-Type字段
    CONTENT_LENGTH请求头中的Content-length字段
    SCRIPT_NAME脚本名称
    REQUEST_URI请求的地址不带参数
    DOCUMENT_URI与$uri相同
    DOCUMENT_ROOT网站的根目录。在server配置中root指令中指定的值
    SERVER_PROTOCOL请求使用的协议,通常是HTTP/1.0或HTTP/1.1
    GATEWAY_INTERFACEcgi 版本
    SERVER_SOFTWAREnginx 版本号,可修改、隐藏
    REMOTE_ADDR客户端IP
    REMOTE_PORT客户端端口
    SERVER_ADDR服务器IP地址
    SERVER_PORT服务器端口
    SERVER_NAME服务器名,域名在server配置中指定的server_name

9.2 常用的四种 Content-Type

  • application/x-www-form-urlencoded
# 请求行
POST http://www.example.com HTTP/1.1
# 请求头
Content-Type: application/x-www-form-urlencoded;charset=utf-8
# 空行
# 请求数据(向服务器提交的数据),用&做间隔,就是application/x-www-form-urlencoded格式
title=test&user=kevin&passwd=32222
  • application/json
# 请求行
POST / HTTP/1.1
# 请求头
Content-Type: application/json;charset=utf-8
# 空行
# 请求数据,如果是json格式就必须是application/json
{"title":"test","sub":[1,2,3]}
  • text/xml
# 请求行
POST / HTTP/1.1
# 请求头
Content-Type: text/xml
# 空行
<?xml version="1.0" encoding="utf8"?>
# 请求数据
<methodcall>
    <methodname color="red">examples.getStateName</methodname>
    <params>
    	<value><i4>41</i4></value>
    </params>
</methodcall>
  • multipart/form-data

  multipart/form-data是传输大文件常用的一种数据格式,在数据刚开始的时候有一个分界线,这个分界线是随机生成的,在结束的时候也有一个分界线。

------WebKitFormBoundaryPpL3BfPQ4cHShsBz

  在分界线下面还有一个Content-DispositionContent-Type,这是对文件属性的描述。文件内容在两个分界线中间,那么用这种格式我们就可以上传多个文件了,一个文件对应一个数据块。不同的数据块都是相同的格式(Content-Disposition + Content-Type + 空行 + 文件内容);当然也可以上传一个大文件,分为多个小数据块。
在这里插入图片描述

  文件的Content-Type不需要我们去记后面写什么,用到的时候直接查表即可:https://tool.oschina.net/commons

# 请求行
POST / HTTP/1.1
# 请求头
Content-Type: multipart/form-data
# 空行
# 发送的数据
------WebKitFormBoundaryPpL3BfPQ4cHShsBz \r\n
Content-Disposition: form-data; name="file"; filename="1.png"
Content-Type: image/png\r\n; md5="xxxxxxxxxx"
\r\n
.............文件内容................
.............文件内容................
------WebKitFormBoundaryPpL3BfPQ4cHShsBz
Content-Disposition: form-data; name="file"; filename="2.png"
\r\n
.............文件内容................
.............文件内容................
------WebKitFormBoundaryPpL3BfPQ4cHShsBz
Content-Disposition: form-data; name="tailor"
\r\n
false
------WebKitFormBoundaryPpL3BfPQ4cHShsBz--

10. fastCGI总结

  1. fastCGI是什么?

    • 运行在服务器端的代码, 帮助服务器处理客户端提交的动态请求
  2. fastCGI干什么?

    • nginx服务器处理不了动态请求,fastCGI帮助服务器处理客户端提交的动态请求
  3. fastCGI怎么用?

    • 前提条件fastCGI和nginx部署在同一台机器上

    • nginx如何转发数据

      # 分析出客户端请求对应的指令 -- /test
      location /test
      {
          # 转发出去
          fastcgi_pass 地址:端口;
          include fastcgi.conf;
      }
      
    • fastcgi如何接收数据

      # 启动, 通过spawn-fcgi启动
      spawn-fcgi -a IP -p port -f ./fcgi
      # 编写fastCGI程序的时候
       - 接收数据: 调用读终端的函数就是接收数据
       - 发送数据: 调用写终端的函数就是发送数据
      
    • fastcgi如何处理数据

      // 编写登录的fastCgI程序
      int main()
      {
          while(FCGI_Accept() >= 0)
          {
              // 1. 接收登录信息 -> 环境变量中
              // post -> 读数据块的长度 CONTENT-LENGTH
              // get -> 从请求行的第二部分读 QUEERY_STRING
              // 2. 处理数据
              // 3. 回发结果 -> 格式假设是json
              printf("Content-type: application/json\r\n");
              printf("\r\n");
              printf("{\"status\":\"OK\"}")
          }
      }
      
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++文件服务器项目—FastCGI—4 的相关文章

随机推荐

  • 堆栈

    栈是一种执行 后进先出 算法的数据结构 设想有一个直径不大 一端开口一端封闭的竹筒 有若干个写有编号的小球 xff0c 小球的直径比竹筒的直径略小 现在把不同编号的小球放到竹筒里面 xff0c 可以发现一种规律 xff1a 先放进去的小球只
  • 大端小端和C实现大小端字节序的转化

    大端小端 小端就是低位字节放在内存的低地址端 xff0c 高位字节放在内存的高地址端 大端就是高位字节放在内存的低地址端 xff0c 低位字节放在内存的高地址端 举一个例子 xff0c 比如数字0x12 34 56 78 xff08 注意7
  • 【计算机图形学/实时渲染】 阴影(GAMES202)

    阴影 对于静态的物体 xff0c 可以使用Lightmap烘焙的方法来获取物体的影子 xff08 静态阴影 xff09 xff0c 而对于动态的物体 xff0c 一般采用的是Shadowmap的技术 光照贴图 xff08 Lightmap
  • 解决Mingw-w64下载太慢问题

    官网下载太慢了 xff0c 我们只用换一个镜像源就可以 1 点击Problems Downloading 2 切换香港的
  • 嵌入式Linux开发8——UART串口通讯

    1 背景知识 1 1 UART通讯格式 串口全称叫做串行接口 xff0c 通常也叫做 COM 接口 xff0c 串行接口指的是数据一个一个的顺序传输 xff0c 通信线路简单 使用两条线即可实现双向通信 xff0c 一条用于发送 xff0c
  • 二叉树笔记

    二叉树 二叉搜索 xff08 排序 查找 xff09 树 二叉查找树 xff08 Binary Search Tree xff09 xff0c xff08 又 xff1a 二叉搜索树 xff0c 二叉排序树 xff09 它或者是一棵空树 x
  • C++面试常见题目

    C 43 43 面试常见题目 c 43 43 编译过程自动类型推导auto和decltype重载 重写 xff08 覆盖 xff09 和隐藏的区别C 43 43 构造函数和析构函数能调用虚函数吗volatile关键词运算符重载格式noexe
  • 计算机网络面试常问问题

    C 43 43 面试 计算机网络常见问题 计算机网络常见问题TCP IP协议笔记TCPTCP的特点及目的序列号与确认应答提高可靠性为什么是三次握手和四次挥手滑动窗口流量控制拥塞控制TCP粘包问题 httphttp和https的区别https
  • Trajectory generation for quadrotor while tracking a moving target in cluttered environment

    四旋翼在杂波环境下跟踪运动目标的轨迹生成 摘要1 文章主要贡献2 前言2 1 轨迹公式2 2 实现结构 3 跟踪轨迹生成3 1 标称路径点生成3 2 可行路径点生成3 3 安全飞行走廊生成3 4 代价函数3 5 强制约束3 6 求解跟踪轨迹
  • 翻译-Frustum PointNets for 3D Object Detection from RGB-D Data

    Frustum PointNets for 3D Object Detection from RGB D Data 摘要介绍相关工作从RGB D数据中检测三维物体基于前视图图像的方法 xff1a 基于鸟瞰图的方法 基于3D的方法 点云的深度
  • Online Trajectory Generation of a MAV for Chasing a Moving Target in 3D Dense Environments

    微型无人机的在线轨迹生成 xff0c 用于在3D密集环境中追踪运动目标 摘要一 介绍二 相关工作A 在障碍物环境中追逐B 通过预先规划安全地生成轨迹 三 问题陈述A 问题设置B 能力C 命名 IV 视点生成A 可见度指标B 具有安全性和可见
  • 配置目标跟踪开源项目traj_gen_vis踩过的坑

    项目地址 https github com icsl Jeon traj gen vis 安装依赖需注意的问题 traj gen with qpoases 需安装ros分支的代码 xff08 这个作者并没有指出 xff0c 坑 xff09
  • cmake arm-none-eabi-gcc for stm32 cpp project

    尝试把原有的stm32工程F1canBootloader用cmake来管理 xff0c 遇到了以下几个坑 xff1a 1 报错 xff0c undefined reference to 96 dso handle 39 CMakeFiles
  • 网络攻防之wireshark抓取登录信息

    使用wireshark抓取登录信息 简介 xff1a Wireshark xff08 前称Ethereal xff09 是一个网络封包分析软件 网络封包分析软件的功能是撷取网络封包 xff0c 并尽可能显示出最为详细的网络封包资料 Wire
  • 头文件互相包含所引发的的问题(深入剖析)

    今天写程序出现了一个让人蛋疼的错误 xff0c 后来发现是由于头文件互相包含所引起的 原本只是简单的以为头文件互相包含只会触发 xff0c 头文件的递归包含 即 xff0c A包含B xff0c 所以才A的头文件里会将B的头文件内容拷贝过来
  • C++11异步操作future和aysnc 、function和bind

    C 43 43 11异步操作future和aysnc function和bind 前言异步操作std future和std aysnc 介绍std future和std aysnc的使用Demostd packaged task 介绍std
  • C++文件服务器项目—FastDFS—1

    C 43 43 文件服务器项目 FastDFS 1 前言1 项目架构2 分布式文件系统2 1 传统文件系统2 2 分布式文件系统 3 FastDFS介绍3 1 fdfs概述3 2 fdfs框架中的三个角色3 3 fdfs三个角色之间的关系3
  • C++文件服务器项目—Redis—2

    C 43 43 文件服务器项目 Redis 2 前言1 数据库类型1 1 基本概念1 2 关系 非关系型数据库搭配使用 2 redis基础知识点2 1 redis安装2 2 redis中的两个角色2 3 redis中数据的组织格式2 4 r
  • C++文件服务器项目—Nginx—3

    C 43 43 文件服务器项目 Nginx 3 前言1 Nginx一些基本概念1 1 Nginx初步认识1 2 正向代理概念理解1 3 反向代理概念理解 2 Nginx的安装与配置2 1 Nginx与相关依赖库的安装2 2 Nginx相关的
  • C++文件服务器项目—FastCGI—4

    C 43 43 文件服务器项目 FastCGI 4 前言1 CGI 概念理解2 FastCGI 概念理解3 FastCGI和spawn fcgi安装4 FastCGI和 Nginx的关系5 Nginx数据转发 修改配置文件6 spawn f