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. JVM JMM

  2. cocos2d-x Loading界面实现资源加载

    有时候场景中的资源加载过多的话就会引起游戏进入的时候很卡,因为那是边加载边显示.在tests例子里面有一个很好的例子叫做TextureCacheTest,里面讲解了如何写loading. #inclu ...

  3. 【转】深圳FAE,想拿高薪还缺什么?

    原文网址:http://www.eefocus.com/KTHR_IC/blog/11-05/222793_e04c8.html KT老胡您好! 我07年本科毕业在一家医疗民营企业从事了3年多的嵌入式 ...

  4. GDKOI2015

    problems http://gdoi.sysu.edu.cn/wp-content/uploads/2015/03/GDKOI-2015-day1.pdf http://gdoi.sysu.edu ...

  5. chrome加载本地js

    通过chrome的扩展功能,可以执行一些本地脚本. 1.如何添加扩展程序 具体做法是:chrome -> 设置 -> 扩展程序 -> 加载正在开发的扩展程序 图(1.1) 图(1.2 ...

  6. python高级编程技巧

    由python高级编程处学习 http://blog.sina.com.cn/s/blog_a89e19440101fb28.html Python列表解析语法[]和生成 器()语法类似 [expr  ...

  7. 推荐C/C++常见的面试题目

    http://blog.163.com/bingqingyujie..5/blog/static/75559361201011861958534/ 里面有详细的面试类型

  8. Android-67-Tomcat启动出错:Server Tomcat v7.0 Server at localhost failed to start.

     错误:Server Tomcat v7.0 Server at localhost failed to start.如图: 唉! ! !!图片上传不上去,悲哀啊!..仅仅能先写着错误提示语吧~~ ...

  9. 设计: ListView 接口,and the missing read-only interfaces in java collection framework

    Java的集合框架以其成功易用的设计征服了很多人(包括我),并且教科书式的诠释了泛型的应用方式. 我也是被 Joshua Bloch 的书引领入门,从中得益良多.我当然不会认为自己在设计上比他懂得更多 ...

  10. Hash表题目整数hash-HDOJ1425(转载)

      哈希表(散列表)的基本原理:使用一个下标范围比较大的数组来存储元素,一般通过设计一个函数(哈希函数,即散列函数),使得每个元素的关键字都与一个函数值(即数组下标)相对应,然后用该数组单元来存储对应 ...