分布式系统学习第四天 fastcgi学习

news/2024/12/1 0:31:55/

目录

1. Nginx作为web服务器处理请求

2. http协议复习

3. fastCGI

3.1 CGI

3.3 fastCGI和spawn-fcgi安装

3.4 nginx && fastcgi

3.5我的总结

其他知识点


1. Nginx作为web服务器处理请求

nginx不能处理动态请求 因此把请求发送给fastCGI对动态请求进行处理

  1. 静态请求

    客户端访问服务器的静态网页, 不涉及任何数据的处理, 如下面的URL:

    http://localhsot/login.html
  2. 动态请求

    客户端会将数据提交给服务器

    # 使用get方式提交数据得到的url
    http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man- http: 协议- localhost: 域名- /login: 服务器端要处理的指令- ? : 连接符, 后边的内容是客户端给服务器提交的数据- & : 分隔符
    动态的url如何找服务器端处理的指令?
    - 去掉协议
    - 去掉域名/IP
    - 去掉端口
    - 去掉?和它后边的内容
    # 如果看到的是请求行, 如何找处理指令?
    POST /upload/UploadAction HTTP/1.1
    GET /?username=tom&phone=123&email=hello%40qq.com&date=2018-01-01&sex=male&class=3&rule=on HTTP/1.1
    1. 找请求行的第二部分- 如果是post, 处理指令就是请求行的第二部分- 如果是get, 处理指令就是请求行的第二部分, ? 以前的内容

2. http协议复习

  1. 请求消息(Request) - 客户端(浏览器)发送给服务器的数据格式

    四部分: 请求行, 请求头, 空行, 请求数据

    • 请求行: 说明请求类型, 要访问的资源, 以及使用的http版本

    • 请求头: 说明服务器要使用的附加信息

    • 空行: 空行是必须要有的, 即使没有请求数据

    • 请求数据: 也叫主体, 可以添加任意的其他数据

    • Get方式提交数据

      第一行: 请求行

      第2-9行: 请求头(键值对)

      第10行: 空行

      get方式提交数据, 没有第四部分, 提交的数据在请求行的第二部分, 提交的数据会全部显示在地址栏中

      GET /?username=tom&phone=123&email=hello%40qq.com&date=2018-01-01&sex=male&class=3&rule=on HTTP/1.1
      Host: 192.168.26.52:6789
      Connection: keep-alive
      Cache-Control: max-age=0
      Upgrade-Insecure-Requests: 1
      User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
      Accept-Encoding: gzip, deflate
      Accept-Language: zh,zh-CN;q=0.9,en;q=0.8
      ​
    • Post方式提交数据

    • 使用get提交数据的话,可能会造成数据的丢失,因为get传递数据是根据请求行传递,也就是url,url缓存一般为8k,如果上传1mb的数据,会导致数据的丢失,而且get是不保密的,因此采用post提交数据

      第一行: 请求行

      第2 -12行: 请求头 (键值对)

      第13行: 空行

      第14行: 提交的数据

      POST / HTTP/1.1
      Host: 192.168.26.52:6789
      Connection: keep-alive
      Content-Length: 84
      Cache-Control: max-age=0
      Upgrade-Insecure-Requests: 1
      Origin: null
      Content-Type: application/x-www-form-urlencoded
      User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36
      Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
      Accept-Encoding: gzip, deflate
      Accept-Language: zh,zh-CN;q=0.9,en;q=0.8
      ​
      username=tom&phone=123&email=hello%40qq.com&date=2018-01-01&sex=male&class=3&rule=on
  2. 响应消息(Response) -> 服务器给客户端发送的数据

    • 四部分: 状态行, 消息报头, 空行, 响应正文

      • 状态行: 包括http协议版本号, 状态码, 状态信息

      • 消息报头: 说明客户端要使用的一些附加信息

      • 空行: 空行是必须要有的

      • 响应正文: 服务器返回给客户端的文本信息

    第一行:状态行

    第2 -11行: 响应头(消息报头)

    第12行: 空行

    第13-18行: 服务器给客户端回复的数据

    HTTP/1.1 200 Ok
    Server: micro_httpd
    Date: Fri, 18 Jul 2014 14:34:26 GMT
    /* 告诉浏览器发送的数据是什么类型 */
    Content-Type: text/plain; charset=iso-8859-1 (必选项)
    /* 发送的数据的长度 */
    Content-Length: 32  
    Location:url
    Content-Language: zh-CN
    Last-Modified: Fri, 18 Jul 2014 08:36:36 GMT
    Connection: close
    ​
    #include <stdio.h>
    int main(void)
    {printf("hello world!\n");return 0;
    }
  3. http状态码

    状态代码有三位数字组成,第一个数字定义了响应的类别,共分五种类别:

    • 1xx:指示信息--表示请求已接收,继续处理

    • 2xx:成功--表示请求已被成功接收、理解、接受

    • 3xx:重定向--要完成请求必须进行更进一步的操作

    • 4xx:客户端错误--请求有语法错误或请求无法实现

    • 5xx:服务器端错误--服务器未能实现合法的请求

3. fastCGI

3.1 CGI

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

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进程,处理完之后再退出该进程

  • 服务器开销大, 效率低

 3.2 fastCGI

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

fastCGI与CGI的区别:

CGI 就是所谓的短生存期应用程序,FastCGI 就是所谓的长生存期应用程序。FastCGI像是一个常驻(long-live)型的CGI,它可以一直执行着,不会每次都要花费时间去fork一次

 

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

  1. 用户通过浏览器访问服务器, 发送了一个请求, 请求的url如上

  2. 服务器接收数据, 对接收的数据进行解析

  3. nginx对于一些登录数据不知道如何处理, nginx将数据发送给了fastcgi程序

  • 通过本地套接字

  • 网络通信的方式

  1. fastCGI程序如何启动

  • 不是有web服务器直接启动

  • 通过一个fastCGI进程管理器启动

  1. fastcgi启动

  • 加载配置 - 可选

  • 连接服务器 - 数据库

  • 循环

    • 服务器有请求 -> 处理

      • 将处理结果发送给服务器

        • 本地套接字

        • 网络通信

    • 没有请求 -> 阻塞

  1. 服务器将fastCGI的处理结果发送给客户端

3.3 fastCGI和spawn-fcgi安装

  1. 安装fastCGI

    ./configure
    make
    - fcgio.cpp:50:14: error: 'EOF' was not declared in this scope
    - 没有包含对应的头文件:- stdio.h - c- cstdio -> c++
    sudo make install
  2. 安装spawn-fcgi(fastcgi进程管理器)

    • 下载地址: WikiStart - spawn-fcgi - lighty labs

    • 安装

      ./configure
      make
      sudo make install

3.4 nginx && fastcgi

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的连接请求。

相当于spawn-fcgi是FastCGI的父进程

 

 

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

  1. 客户端访问, 发送请求

  2. nginx web服务器, 无法处理用户提交的数据

  3. spawn-fcgi - 通信过程中的服务器角色

    • 被动接收数据

    • 在spawn-fcgi启动的时候给其绑定IP和端口

  4. fastCGI程序

    • 程序猿写的 -> login.c -> 可执行程序( login )

    • 使用 spawn-fcgi 进程管理器启动 login 程序, 得到一进程

nginx的数据转发 - 需要修改nginx的配置文件 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
端口: 找一个空闲的没有被占用的端口即可

spawn-fcgi如何启动

# 前提条件: 程序猿的fastCGI程序已经编写完毕 -> 可执行文件 login
spawn-fcgi -a IP地址 -p 端口 -f fastcgi可执行程序- IP地址: 应该和nginx的 fastcgi_pass 配置项对应- 需要将域名转换为ip地址 因为spawn-fcgi启动的时候只能解析ip地址- nginx: localhost   ->   IP: 127.0.0.1- nginx: 127.0.0.1	 ->   IP: 127.0.0.1- nginx: 192.168.1.100   ->    IP: 192.168.1.100
- 端口:应该和nginx的 fastcgi_pass 中的端口一致

fastCGI程序怎么写

实际上和spawn-fcgi采用了网络通信的方法,在写的时候,spawn将标准输入输出进行了dup2操作,将其重定向到了通信的路口,因此我们在写的时候只需要采用getchar或者fread就可以对数据进行读取,使用printf或者putchar可以对数据进行发送,采用 FCGI_Accept()函数进行阻塞等待数据的发送。

// http://localhost/login?user=zhang3&passwd=123456&age=12&sex=man
// 要包含的头文件
#include "fcgi_config.h" // 可选
#include "fcgi_stdio.h" // 必须的, 编译的时候找不到这个头文件, find->path , gcc -I
// 编写代码的流程
// 使用get的时候 关注QUERY_STRING 使用post的时候 关注CONTENT_LENGTH
int main()
{// FCGI_Accept()是一个阻塞函数, nginx给fastcgi程序发送数据的时候解除阻塞// 阻塞等待数据来while (FCGI_Accept() >= 0) {// 1. 接收数据// 1.1 get方式提交数据 - 数据在请求行的第二部分// user=zhang3&passwd=123456&age=12&sex=manchar *text = getenv("QUERY_STRING"); // 1.2 post方式提交数据char *contentLength = getenv("CONTENT_LENGTH");// 根据长度大小判断是否需要循环// 2. 按照业务流程进行处理// 3. 将处理结果发送给nginx// 数据回发的时候, 需要告诉nginx处理结果的格式 - 假设是html格式// 告诉nginx类型之后 nginx会将类型告诉浏览器 浏览器才能对相应的类型进行解析操作printf("Content-type: text/html\r\n");printf("<html>处理结果</html>");}
}

使用get方法提交的数据得到的打印结果

 使用post提交数据得到的打印结果

 环境变量在fastcgi.conf中,我们书写程序的时候会使用到这些环境变量,用于获取到发送过来的数据。

3.5我的总结

 使用fastcgi
/*
如果不进行配置 则直接提交会返回404
因为服务器转接的地址是不存在的 因此需要看提交之后地址转向了哪
然后在配置文件中对转接的地址进行fastcgi配置
假设转接的地址是 /Myupload

在nginx.conf文件进行配置以下选项
location /Myupload
{
    fastcgi_pass 127.0.0.1:10000;
    include fastcgi.conf;
}

sudo nginx -s reload 重启

配置完之后再次点击上传 报的错将不是404 而是处理请求的一个错误
/*

动态库找不到的方法
假设生成的文件是app
ldd app 可以查看到生成的文件所以来的动态库,如果不存在则会提示
sudo find / -name "xxx.so" 搜索动态库的位置
如果不在linux系统的制定目录下 可以进行以下几种操作
法1、将路径添加到LD_LIBRARY_PATH
法2、将文件添加到 /etc/ld.so.conf
如想加/usr/local/lib 直接加到下一行即可
加完之后需要执行 sudo ldconfig 生效

 

##复习

Nginx

  1. 是什么?

    • 开源的框架

      • 库: 一套API

      • 框架: (可以)有一套API, 有一套事件处理机制

  2. 能干什么?

    • web服务器

      • http协议

    • 反向代理

      • 实现web服务器的负载均衡

    • 邮件服务器

      • pop3

  3. 怎么干事儿?

    • web服务器

      # 部署静态网页
      1. 制作出来, 并且部署到对应的资源目录中
      2. 根据客户端的请求, 在服务器端添加对应的 location处理指令 - nginx.conf
      3. 重新加载nginx.conf配置文件
      客户端请求的url: http://xxxx.com/hello/login.html- 去掉协议: http- 去掉域名/IP:- 去掉端口- 去掉尾部的文件名
    • 反向代理服务器

      1. 找到反向代理服务器 的配置文件: nginx.conf
      2. 找模块 http -> server
      server{listen: 80; # 客户端访问反向代理服务器的时候使用的端口server_name: localhost; # 域名, 客户端访问反向代理服务器时候, 使用的地址# 配置如何转发, 根据客户端的请求的url找到对应的转发指令location /{# 设置转发地址proxy_pass http://test.com;}    location /login{# 设置转发地址proxy_pass http://test.com;} 
      }
      # 设置代理
      upstream test.com
      {# web服务器的地址信息server 192.168.1.100:80;server 192.168.1.101:80;
      }
      ​
      # 192.168.1.100 web服务器
      http->server
      server{location /{# 设置转发地址root xxx;}    location /login{# 设置转发地址xxxx;} 
      }
      # 192.168.1.101 web服务器
      http->server
      server{location /{# 设置转发地址root xxx;}    location /login{# 设置转发地址xxxx;} 
      }

其他知识点

  1. 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
  2. 客户端使用Post提交数据常用方式

    • Http协议规定 POST 提交的数据必须放在消息主体(entity-body)中,但协议并没有规定数据必须使用什么编码方式。

    • 开发者完全可以自己决定消息主体的格式

    • 数据发送出去,还要服务端解析成功才有意义, 服务端通常是根据请求头(headers)中的

    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
      # 空行
      # 请求数据(向服务器提交的数据)
      title=test&user=kevin&passwd=32222
    • application/json

      POST / HTTP/1.1
      Content-Type: application/json;charset=utf-8
      {"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>
      ​
      <font color="red">nihao, shijie</font>
    • multipart/form-data 传输大文件的类型 用了不同的数据块 每个数据块之间是独立的 这样就可以发送大文件

      POST / HTTP/1.1
      Content-Type: multipart/form-data
      # 发送的数据
      ------WebKitFormBoundaryPpL3BfPQ4cHShsBz \r\n
      Content-Disposition: form-data; name="file"; filename="qw.png"
      Content-Type: image/png\r\n; md5="xxxxxxxxxx"
      \r\n
      .............文件内容................
      .............文件内容................
      ------WebKitFormBoundaryPpL3BfPQ4cHShsBz--
      Content-Disposition: form-data; name="file"; filename="qw.png"
      Content-Type: image/png\r\n; md5="xxxxxxxxxx"
      \r\n
      .............文件内容................
      .............文件内容................
      ------WebKitFormBoundaryPpL3BfPQ4cHShsBz--
  3. strtol 函数使用

    // 将数字类型的字符串 -> 整形数
    long int strtol(const char *nptr, char **endptr, int base);- 参数nptr: 要转换的字符串 - 数字类型的字符串: "123", "0x12", "0776"- 参数endptr: 测试时候使用, 一般指定为NULL- 参数base: 进制的指定- 10 , nptr = "123456", 如果是"0x12"就会出错- 8  , nptr = "0345"- 16,  nptr = "0x1ff"
    ​
    char* p = "123abc";
    char* pt = NULL;
    strtol(p, &pt, 10);- 打印pt的值: "abc"
    

http://www.ppmy.cn/news/550931.html

相关文章

Google play developer谷歌开发者注册和使用中的常见问题和解决方案

1.谷歌开发者注册时候所使用的网络问题 解决方案&#xff1a; 1.购买大厂的虚拟服务器&#xff0c;阿里云、亚马逊aws。 这里需要注意的点就是&#xff0c;找到稳定的上网环境&#xff0c;这点为后续的账号稳定有很好的帮助&#xff1b;建议使用日本、香港的相关节点。在这里…

数据库判断分解的无损连接性

例题 关系模式R&#xff08;ABCDE&#xff09;&#xff0c;F{A->C,C->D,B->C,DE->C,CE->A} 若分解成R1(AD)R2(AB)R3(BC)R4(CDE)R5(AE)判断是否具有无损连接性 画出如下表格如第一行&#xff1a;AD&#xff0c;那么在A&#xff0c;D的地方填入&#xff0c;i表…

Google play谷歌应用商店 APP上包上架的一些策略和技巧

1.服务端接口&#xff1a;服务器对应的IP、域名&#xff0c;只用在一个App内。尤其是做马甲包的&#xff0c;经常是一套服务器环境用遍所有包&#xff0c;基本就是团灭。所以合理的隔离服务端接口&#xff0c;一定会延长app的在线时间。 这里有小技巧&#xff1a;比如做一些便…

解决申请 Googl e账号填写电话号码不能验证的问题

使用google账号的方便之处是不管在哪里&#xff0c;只用在chorm登录google账号你自己收藏的书签和扩展工具都会同步&#xff0c;对于开发人员来说是非常好用的&#xff0c;所以给大家介绍下我自己申请google 账号的过程&#xff0c;希望对你有帮助。 方法很简单&#xff1a;用…

Google Voice 虚拟号码

你是否有想要登陆外网&#xff0c;却没有美国手机号来创建帐号的难题&#xff1f;&#x1f62d;&#x1f62d;&#x1f62d; 你又是否有一个帐号不够用却没有别的电话卡的窘境&#xff1f;&#x1f62d;&#x1f62d;&#x1f62d;&#x1f62d; 来看看本文教程 详细介绍&am…

谷歌gmail注册入口_Google向GMail添加免费电话语音通话

谷歌gmail注册入口 Do you have a GMail account (who doesn’t?) From today, you may be lucky enough to notice a new “Call Phone” option in your Chat box… 从今天开始,您是否拥有GMail帐户(没有?),您可能很幸运在聊天框中注意到一个新的“呼叫电话”选项… Unl…

Google Play 注册开发者注意事项

注册开发者所需的信息必须是未使用的&#xff0c;尤其是在有过封号的情况下尤为重要 下面整理了常见的所需资料 1. 电脑or服务器 保证该电脑未登录谷歌相关账号&#xff0c;同时保证一台电脑对应一个开发者账号 整理以下几种方式&#xff0c;按照我们操作过的保险方式排序&…

电话用计算机接听,怎么用电脑打电话-现在你可以在电脑上接听安卓手机的电话了...

对于那些使用笔记本电脑和手机的人来说,长期以来梦寐以求的功能是两者之间的无缝切换,对于那些不希望停止在一个屏幕上所做的事情,转而在更小的屏幕上做其他事情的人来说也是如此。现在,微软通过让你直接在电脑上打电话和接电话,帮助消除了这种隔阂。你还可以直接将电话发…