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. BZOJ3713: [PA2014]Iloczyn

    3713: [PA2014]Iloczyn Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 206  Solved: 112[Submit][Status ...

  2. cf494A Treasure

    A. Treasure time limit per test 2 seconds memory limit per test 256 megabytes input standard input o ...

  3. linux内核--中断和中断处理(一)

        让硬件在需要的时候再向内核发出信号.这就是中断机制,先讨论中断,进而讨论内核如何使用所谓的中断处理函数处理对应的中断. 一.中断   1)中断     中断使得硬件得以发出通知给处理器.例如, ...

  4. 第32讲 UI组件之 时间日期控件DatePicker和TimePicker

    第32讲 UI组件之 时间日期控件DatePicker和TimePicker 在Android中,时间日期控件相对来说还是比较丰富的.其中, DatePicker用来实现日期输入设置,    Time ...

  5. JAVA并发实现五(生产者和消费者模式wait和notify方式实现)

    package com.subject01; import java.util.PriorityQueue; /** * 通过wait和notify 实现 * 生产者-消费者模型:当队列满时,生产者需 ...

  6. eclispe远程调试tomcat

    在eclispe中新建web应用,名字叫webtest.里面只有一个HelloServlet.Web.xml配置如下. 修改tomcat的启动脚本startup.bat.复制startup.bat为s ...

  7. (转)iOS7界面设计规范(12) - UI基础 - 品牌

    重要:这是针对于正在开发中的API或技术的预备文档(预发布版本).虽然该文档在技术精确度上经过了严格的审核,但并非最终版本,仅供苹果开发者计划的注册会员使用.苹果提供这份机要文档的目的,是帮助你按照文 ...

  8. [Redux] Generating Containers with connect() from React Redux (VisibleTodoList)

    Learn how to use the that comes with React Redux instead of the hand-rolled implementation from the ...

  9. 为iPhone 6设计自适应布局

    Apple从iOS 6加入了Auto Layout后开始就比较委婉的开始鼓励.建议开发者使用自适应布局,但是到目前为止,我感觉大多数开发者一直在回避这个问题,不管是不是由于历史原因造成的,至少他们在心 ...

  10. C-二维数组,多维数组

    -----二维数组      ->在数组定义当中,行数和列数需要用常量定义      ->在定义的时候如果没有数值进行填充,则补零      ->第一个数是行,第二个数是列     ...