FastCgi不仅可以用于webserver与PHP的交互,也可用于任何两个应用之间的交互,PHPer用的比较多的应该就是用于两个子系统之间的交互。 比如A系统和B系统分部独立的部署在两台机器上,其之间通信用的比较多的http协议通信,但通过fastcgi协议通信可以更加简洁、高效。 下面将写个的程序模拟webserver与PHP交互: 首先我们看下webserver与fastcgi应用(如PHP)的交互过程:

PHP $_SERVER数组中变量都是webserver通过FCGI_PARAMS传递到PHP的,关于fastcgi协议详情请查看:fastcgi协议 下面的程序主要实现的是: 执行PHP所在机器/opt/data/www/index.php文件: Index.php文件的内容为:

echo "Hollo World!\n";
echo $_SERVER['MY_NAME']."\n";

 

其中$_SERVER['MY_NAME']是我们通过程序传递过来的变量。 程序具体如下(只是简单模拟交互,程序可能不完善): Fasctcgi.h:

 
/*

* fastcgi.h --

*

*   Defines for the FastCGI protocol.

*

*

* Copyright (c) 1995-1996 Open Market, Inc.

*

* See the file "LICENSE.TERMS" for information on usage and redistribution

* of this file, and for a DISCLAIMER OF ALL WARRANTIES.

*

* $Id: fastcgi.h,v 1.1.1.1 1997/09/16 15:36:32 stanleyg Exp $

*/

#ifndef _FASTCGI_H

#define _FASTCGI_H

/*

* Listening socket file number

*/

#define FCGI_LISTENSOCK_FILENO 0

typedef struct {

unsigned char version;

unsigned char type;

unsigned char requestIdB1;

unsigned char requestIdB0;

unsigned char contentLengthB1;

unsigned char contentLengthB0;

unsigned char paddingLength;

unsigned char reserved;

} FCGI_Header;

#define FCGI_MAX_LENGTH 0xffff

/*

* Number of bytes in a FCGI_Header.  Future versions of the protocol

* will not reduce this number.

*/

#define FCGI_HEADER_LEN  8

/*

* Value for version component of FCGI_Header

*/

#define FCGI_VERSION_1           1

/*

* Values for type component of FCGI_Header

*/

#define FCGI_BEGIN_REQUEST       1

#define FCGI_ABORT_REQUEST       2

#define FCGI_END_REQUEST         3

#define FCGI_PARAMS              4

#define FCGI_STDIN               5

#define FCGI_STDOUT              6

#define FCGI_STDERR              7

#define FCGI_DATA                8

#define FCGI_GET_VALUES          9

#define FCGI_GET_VALUES_RESULT  10

#define FCGI_UNKNOWN_TYPE       11

#define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)

/*

* Value for requestId component of FCGI_Header

*/

#define FCGI_NULL_REQUEST_ID     0

typedef struct {

unsigned char roleB1;

unsigned char roleB0;

unsigned char flags;

unsigned char reserved[5];

} FCGI_BeginRequestBody;

typedef struct {

FCGI_Header header;

FCGI_BeginRequestBody body;

} FCGI_BeginRequestRecord;

/*

* Mask for flags component of FCGI_BeginRequestBody

*/

#define FCGI_KEEP_CONN  1

/*

* Values for role component of FCGI_BeginRequestBody

*/

#define FCGI_RESPONDER  1

#define FCGI_AUTHORIZER 2

#define FCGI_FILTER     3

typedef struct {

unsigned char appStatusB3;

unsigned char appStatusB2;

unsigned char appStatusB1;

unsigned char appStatusB0;

unsigned char protocolStatus;

unsigned char reserved[3];

} FCGI_EndRequestBody;

typedef struct {

FCGI_Header header;

FCGI_EndRequestBody body;

} FCGI_EndRequestRecord;

/*

* Values for protocolStatus component of FCGI_EndRequestBody

*/

#define FCGI_REQUEST_COMPLETE 0

#define FCGI_CANT_MPX_CONN    1

#define FCGI_OVERLOADED       2

#define FCGI_UNKNOWN_ROLE     3

/*

* Variable names for FCGI_GET_VALUES / FCGI_GET_VALUES_RESULT records

*/

#define FCGI_MAX_CONNS  "FCGI_MAX_CONNS"

#define FCGI_MAX_REQS   "FCGI_MAX_REQS"

#define FCGI_MPXS_CONNS "FCGI_MPXS_CONNS"

typedef struct {

unsigned char type;

unsigned char reserved[7];

} FCGI_UnknownTypeBody;

typedef struct {

FCGI_Header header;

FCGI_UnknownTypeBody body;

} FCGI_UnknownTypeRecord;

#endif   /* _FASTCGI_H */

  fastcgi

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <sys/socket.h>

#include <arpa/inet.h>

#include <string.h>

#include <netinet/in.h>

#include <errno.h>

#include "fastcgi.h"

typedef struct sockaddr SA;

#define PARAMS_BUFF_LEN 1024

#define CONTENT_BUFF_LEN 1024

/*

*----------------------------------------------------------------------

*

* MakeHeader --

*

*      Constructs an FCGI_Header struct.

*

*----------------------------------------------------------------------

*/

static FCGI_Header MakeHeader(

int type,

int requestId,

int contentLength,

int paddingLength)

{

FCGI_Header header;

header.version = FCGI_VERSION_1;

header.type             = (unsigned char) type;

header.requestIdB1      = (unsigned char) ((requestId     >> 8) & 0xff);

header.requestIdB0      = (unsigned char) ((requestId         ) & 0xff);

header.contentLengthB1  = (unsigned char) ((contentLength >> 8) & 0xff);

header.contentLengthB0  = (unsigned char) ((contentLength     ) & 0xff);

header.paddingLength    = (unsigned char) paddingLength;

header.reserved         =  0;

return header;

}

/*

*----------------------------------------------------------------------

*

* MakeBeginRequestBody --

*

*      Constructs an FCGI_BeginRequestBody record.

*

*----------------------------------------------------------------------

*/

static FCGI_BeginRequestBody MakeBeginRequestBody(

int role,

int keepConnection)

{

FCGI_BeginRequestBody body;

body.roleB1 = (unsigned char) ((role >>  8) & 0xff);

body.roleB0 = (unsigned char) (role         & 0xff);

body.flags  = (unsigned char) ((keepConnection) ? FCGI_KEEP_CONN : 0);

memset(body.reserved, 0, sizeof(body.reserved));

return body;

}

static void FCGI_BuildNameValueBody(

char *name,

int nameLen,

char *value,

int valueLen,

unsigned char *bodyBuffPtr,

int *bodyLenPtr) {

unsigned char *startBodyBuffPtr = bodyBuffPtr;

if (nameLen < 0x80) {

*bodyBuffPtr++ = (unsigned char) nameLen;

} else {

*bodyBuffPtr++ = (unsigned char) ((nameLen >> 24) | 0x80);

*bodyBuffPtr++ = (unsigned char) (nameLen >> 16);

*bodyBuffPtr++ = (unsigned char) (nameLen >> 8);

*bodyBuffPtr++ = (unsigned char) nameLen;

}

if (valueLen < 0x80) {

*bodyBuffPtr++ = (unsigned char) valueLen;

} else {

*bodyBuffPtr++ = (unsigned char) ((valueLen >> 24) | 0x80);

*bodyBuffPtr++ = (unsigned char) (valueLen >> 16);

*bodyBuffPtr++ = (unsigned char) (valueLen >> 8);

*bodyBuffPtr++ = (unsigned char) valueLen;

}

while(*name != '\0'){

*bodyBuffPtr++ = *name++;

}

while(*value != '\0'){

*bodyBuffPtr++ = *value++;

}

*bodyLenPtr = bodyBuffPtr - startBodyBuffPtr;

}

int main(){

int sockfd,count,requestId=1,result;

struct sockaddr_in serveraddr;

if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){

perror("socket");

}

bzero((char *)&serveraddr, sizeof(serveraddr));

serveraddr.sin_family = AF_INET;

serveraddr.sin_addr.s_addr = inet_addr("127.0.0.1");

serveraddr.sin_port = htons((unsigned short) 9000);

result = connect(sockfd ,(SA *)&serveraddr, sizeof(serveraddr));

if(result < 0){

perror("bind");

exit(1);

}

FCGI_BeginRequestRecord beginRecord;

beginRecord.header = MakeHeader(FCGI_BEGIN_REQUEST, requestId,

sizeof(beginRecord.body), 0);

beginRecord.body = MakeBeginRequestBody(FCGI_RESPONDER, 0);

count = write(sockfd, (char *)&beginRecord, sizeof(beginRecord));

if(count != sizeof(beginRecord)) {

printf("write error.len:%d,send:%d",sizeof(beginRecord),count);

perror("write");

exit(1);

}

//传递SCRIPT_FILENAME参数

char name1[] = "SCRIPT_FILENAME";

char value1[] = "/opt/data/www/index.php";

unsigned char bodyBuff[PARAMS_BUFF_LEN];

bzero(bodyBuff,PARAMS_BUFF_LEN);

int nameLen, valueLen, bodyLen;

nameLen = strlen(name1);

valueLen = strlen(value1);

FCGI_BuildNameValueBody(

name1,

nameLen,

value1,

valueLen,

&bodyBuff[0],

&bodyLen);

FCGI_Header nameValueHeader;

nameValueHeader = MakeHeader(FCGI_PARAMS, requestId,

bodyLen, 0);

int valuenameRecordLen = bodyLen+FCGI_HEADER_LEN;

char valuenameRecord[valuenameRecordLen];

memcpy(valuenameRecord, (char *)&nameValueHeader, FCGI_HEADER_LEN);

memcpy(valuenameRecord+FCGI_HEADER_LEN, bodyBuff, bodyLen);

count = write(sockfd, (char *)&valuenameRecord, valuenameRecordLen);

if(count != valuenameRecordLen) {

printf("write aluenameRecord error.len:%d,send:%d",valuenameRecordLen,count);

perror("write");

exit(1);

}

//传递MY_NAME

char name2[] = "MY_NAME";

char value2[] = "laiwenhui";

bzero(bodyBuff,PARAMS_BUFF_LEN);

nameLen = strlen(name2);

valueLen = strlen(value2);

FCGI_BuildNameValueBody(

name2,

nameLen,

value2,

valueLen,

&bodyBuff[0],

&bodyLen);

nameValueHeader = MakeHeader(FCGI_PARAMS, requestId,

bodyLen, 0);

valuenameRecordLen = bodyLen+FCGI_HEADER_LEN;

char myvaluenameRecord[valuenameRecordLen];

memcpy(myvaluenameRecord, (char *)&nameValueHeader, FCGI_HEADER_LEN);

memcpy(myvaluenameRecord+FCGI_HEADER_LEN, bodyBuff, bodyLen);

count = write(sockfd, (char *)&myvaluenameRecord, valuenameRecordLen);

if(count != valuenameRecordLen) {

printf("write aluenameRecord error.len:%d,send:%d",valuenameRecordLen,count);

perror("write");

exit(1);

}

//结束请求

FCGI_Header endHeader;

endHeader = MakeHeader(FCGI_PARAMS, requestId,

0, 0);

count = write(sockfd, (char *)&endHeader, FCGI_HEADER_LEN);

if(count != FCGI_HEADER_LEN){

perror("write");

exit(1);

}

//读取返回头信息

FCGI_Header responderHeader;

char content[CONTENT_BUFF_LEN];

int contenLen;

char tmp[8];

while(read(sockfd, &responderHeader, FCGI_HEADER_LEN)>0){

if(responderHeader.type == FCGI_STDOUT){

contenLen = (responderHeader.contentLengthB1<<8)+(responderHeader.contentLengthB0);

bzero(content,CONTENT_BUFF_LEN);

count = read(sockfd,content,contenLen);

if(count != contenLen){

perror("read");

}

fprintf(stdout,"%s",content);

//跳过填充部分

if(responderHeader.paddingLength>0){

count = read(sockfd,tmp,responderHeader.paddingLength);

if(count != responderHeader.paddingLength){

perror("read");

}

}

}else if(responderHeader.type == FCGI_STDERR){

contenLen = (responderHeader.contentLengthB1<<8)+(responderHeader.contentLengthB0);

bzero(content,CONTENT_BUFF_LEN);

count = read(sockfd,content,contenLen);

if(count != contenLen){

perror("read");

}

fprintf(stdout,"error:%s\n",content);

//跳过填充部分

if(responderHeader.paddingLength>0){

//long int n=lseek(sockfd,responderHeader.paddingLength,SEEK_CUR);

count = read(sockfd,tmp,responderHeader.paddingLength);

if(count != responderHeader.paddingLength){

perror("read");

}

}

}else if(responderHeader.type == FCGI_END_REQUEST){

FCGI_EndRequestBody endRequest;

count = read(sockfd,&endRequest,8);

if(count != 8){

perror("read");

}

fprintf(stdout,"\nendRequest:appStatus:%d,protocolStatus:%d\n",(endRequest.appStatusB3<<24)+(endRequest.appStatusB2<<16)

+(endRequest.appStatusB1<<8)+(endRequest.appStatusB0),endRequest.protocolStatus);

}

}

close(sockfd);

return 0;

}

  

编译:gcc -Wall -g -o fastcgi fastcgi.c ./fastcgi执行结果为:

X-Powered-By: PHP/5.2.  

Content-type: text/html  

Hollo World!  

laiwenhui  

endRequest:appStatus:,protocolStatus: 

转载自ITCoder

原文链接:http://www.itcoder.me/?p=250

(转)fastcgi协议的简单实现的更多相关文章

  1. CGI 和 FastCGI 协议的运行原理

    目录 介绍 深入CGI协议 CGI的运行原理 CGI协议的缺陷 深入FastCGI协议 FastCGI协议运行原理 为什么是 FastCGI 而非 CGI 协议 CGI 与 FastCGI 架构 再看 ...

  2. PHP 进阶之路 - 深入理解 FastCGI 协议以及在 PHP 中的实现

    在讨论 FastCGI 之前,不得不说传统的 CGI 的工作原理,同时应该大概了解 CGI 1.1 协议 传统 CGI 工作原理分析 客户端访问某个 URL 地址之后,通过 GET/POST/PUT ...

  3. 【转】CGI 和 FastCGI 协议的运行原理

    介绍 深入CGI协议 CGI的运行原理 CGI协议的缺陷 深入FastCGI协议 FastCGI协议运行原理 为什么是 FastCGI 而非 CGI 协议 CGI 与 FastCGI 架构 再看 Fa ...

  4. 依据 smtp协议的简单golang 的发邮件实现

    依据 smtp协议的简单golang 的发邮件实现 协议格式如下 From:sender_user@demo.net To:to_user@demo.net Subject:这是主题 Mime-Ver ...

  5. 基于LNMP(fastcgi协议)环境部署、原理介绍以及fastcgi_cache配置以及upstream模块负载均衡讲解

    ngx_http_proxy_module只能反向代理后端使用HTTP协议的主机.而ngx_http_fastcgi_module只能反向代理后端使用FPM或者使用FastCGI协议的客户端. 一.部 ...

  6. fastcgi协议解析(nginx)

    请求NGINX ->[ {(post data) +> (NGX_HTTP_FASTCGI_STDIN)} * N +> {(environment variables) +> ...

  7. fastcgi协议之一:定义

    参考 深入理解fastcgi协议以及在php中的实现 https://mengkang.net/668.html fastcgi协议规范内容 http://andylin02.iteye.com/bl ...

  8. 采用tcp协议和UDP协议实现简单的聊天功能

    Date: 2019-06-19 Author: Sun 一. Python3输出带颜色字体 实现过程: ​ 终端的字符颜色是用转义序列控制的,是文本模式下的系统显示功能,和具体的语言无关. ​ 转义 ...

  9. FastCGI协议分析

    不知道什么时候,就开始有了让HomeServer支持PHP的念头.于是分析起了FastCGI协议.FastCGI用于WebServer与WebApplication之间的通讯,例如Apache与PHP ...

随机推荐

  1. java进阶计划

    鉴于自己在java 的学习过程中,像是无头苍蝇一样,东扎一把,西戳一下,没有一个明确的方向,也没有一个比较明确的方面,所以有了这个大致的计划. 计划的目标: 1. java本身的目标 对线程(thre ...

  2. hdu5014:number sequence对称思想

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5014 题目大意:给定数组 a[]={0,1,2......n} 求一个数组b[] 元素也为0.... ...

  3. python3-day4(yield)

    1.yield 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一 ...

  4. [RxJS] Completing a Stream with TakeWhile

    Subscribe can take three params: subscribe( (x)=> console.log(x), err=> console.log(err), ()=& ...

  5. World Wind Java开发之十五——载入三维模型

    之前的一篇博客是关于载入粗三维模型的,见http://blog.csdn.net/giser_whu/article/details/43452703,这个地方还存在着不能载入纹理的问题,一直没呢解决 ...

  6. MDM 证书申请流程(vendor及customer)

    整个流程分为两部分:vendor,customer. 一.Vendor 1.成为一个 MDM Vendor 1) 首先你须要拥有一个 Apple Enterprise account($299/年). ...

  7. LVM管理

    一.步骤: 1.创建新的分区,并修改分区类型为8e 2.创建物理卷PV 3.将新建的PV添加到要扩展的VG中 4.用命令lvextend或lvresize来将新加入的PE添加到要扩展的LV中 5.用命 ...

  8. Python进阶之路---1.3python环境搭建

      python环境安装 windows python环境安装 下载安装包     https://www.python.org/downloads/ 安装并指定安装目录     C:\python2 ...

  9. IOS6和IOS7的屏幕适配问题

    自从IOS7出来以后,以前写在IOS6上或者更低版本的程序,跑在IOS7的模拟器上就会出现一些问题.最大的问题就是,所有的UI空间都会统一向上移动20个点(如果空间的y值为0,就会被StatusBar ...

  10. <经验杂谈>C#/.Net字符串操作方法小结

    字符串操作是C#中最基本的.最常见的.也是用的最多的,以下我总结 了几种常见的方法 1.把字符串按照分隔符转换成 List /// <summary> /// 把字符串按照分隔符转换成 L ...