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. js全局函数

    http://www.w3cschool.cc/jsref/jsref-obj-global.html 以前没搞懂JS的全局函数,全局函数和window对象的函数不一样.全局函数不属于任何一个内置对象 ...

  2. NOI2012 美食节

    http://www.lydsy.com/JudgeOnline/problem.php?id=2879 费用流. 我们发现,每个厨师做的倒数第k道菜对总等待时间的贡献为k*做这道菜的时间. 将每个厨 ...

  3. jsDelivr - Free open source CDN for javascript libraries, jQuery plugins, CSS frameworks, Fonts and more

    jsDelivr - Free open source CDN for javascript libraries, jQuery plugins, CSS frameworks, Fonts and ...

  4. c语言二维数组变色龙之死字的打印

    1 #include <stdio.h> #include <stdlib.h> void main() { ][]= { {'#','#','#',' ','#','#',' ...

  5. IT English Collection(9) of Objective-C

    1 前言 今天我们来解除一篇有关Objective-C的介绍文章,详情如下. 2 详述 2.1 原文 Objective-C defines a small but powerful set of e ...

  6. cocos2d-x 3.6版连连看

    写个连连看来讲游戏开发,我认为实例解说效果会好一些. 终端以下cd到源代码文件夹,敲命令: cocos new LLK -p com.goonear.llk -l cpp -d ./Goonear 脚 ...

  7. 解决如何让AsyncTask终止操作

    受到这个的启发终于结局了如何在AsyncTask运行中终止其操作. 单纯的onCancelled(true)是不行的 下面把代码贴出来~实现了登陆功能. AsyncTask简介,它使创建需要与用户界面 ...

  8. timed out waiting for input: auto-logout

    The ssh "timed out waiting for input: auto-logout" messages is generated by ssh upon reach ...

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

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

  10. VPS,虚拟主机,云主机,独立服务器区别

    作者:张朝权链接:http://www.zhihu.com/question/25507629/answer/105594087来源:知乎著作权归作者所有,转载请联系作者获得授权.   独立服务器独立 ...