(转)fastcgi协议的简单实现
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
(转)fastcgi协议的简单实现的更多相关文章
- CGI 和 FastCGI 协议的运行原理
目录 介绍 深入CGI协议 CGI的运行原理 CGI协议的缺陷 深入FastCGI协议 FastCGI协议运行原理 为什么是 FastCGI 而非 CGI 协议 CGI 与 FastCGI 架构 再看 ...
- PHP 进阶之路 - 深入理解 FastCGI 协议以及在 PHP 中的实现
在讨论 FastCGI 之前,不得不说传统的 CGI 的工作原理,同时应该大概了解 CGI 1.1 协议 传统 CGI 工作原理分析 客户端访问某个 URL 地址之后,通过 GET/POST/PUT ...
- 【转】CGI 和 FastCGI 协议的运行原理
介绍 深入CGI协议 CGI的运行原理 CGI协议的缺陷 深入FastCGI协议 FastCGI协议运行原理 为什么是 FastCGI 而非 CGI 协议 CGI 与 FastCGI 架构 再看 Fa ...
- 依据 smtp协议的简单golang 的发邮件实现
依据 smtp协议的简单golang 的发邮件实现 协议格式如下 From:sender_user@demo.net To:to_user@demo.net Subject:这是主题 Mime-Ver ...
- 基于LNMP(fastcgi协议)环境部署、原理介绍以及fastcgi_cache配置以及upstream模块负载均衡讲解
ngx_http_proxy_module只能反向代理后端使用HTTP协议的主机.而ngx_http_fastcgi_module只能反向代理后端使用FPM或者使用FastCGI协议的客户端. 一.部 ...
- fastcgi协议解析(nginx)
请求NGINX ->[ {(post data) +> (NGX_HTTP_FASTCGI_STDIN)} * N +> {(environment variables) +> ...
- fastcgi协议之一:定义
参考 深入理解fastcgi协议以及在php中的实现 https://mengkang.net/668.html fastcgi协议规范内容 http://andylin02.iteye.com/bl ...
- 采用tcp协议和UDP协议实现简单的聊天功能
Date: 2019-06-19 Author: Sun 一. Python3输出带颜色字体 实现过程: 终端的字符颜色是用转义序列控制的,是文本模式下的系统显示功能,和具体的语言无关. 转义 ...
- FastCGI协议分析
不知道什么时候,就开始有了让HomeServer支持PHP的念头.于是分析起了FastCGI协议.FastCGI用于WebServer与WebApplication之间的通讯,例如Apache与PHP ...
随机推荐
- Spring注解 @Resource和@Autowired
@Resource和@Autowired两者都是做bean的注入使用.其实@Resource并不是Spring的注解,他的包是javax.annotation.Resource 需要导入.但是Spri ...
- 构建一个基于 Spring 的 RESTful Web Service
本文详细介绍了基于Spring创建一个“hello world” RESTful web service工程的步骤. 目标 构建一个service,接收如下HTTP GET请求: http://loc ...
- 论 <%@taglib prefix="s" uri="/struts-tags" %> 的重要性
前段时间在做项目的时候,碰到这个问题 结果是相应的内容显示不出来,原来是忘了这句很关键的引入:<%@taglib prefix="s" uri="/struts-t ...
- testng 提供参数
获取页面元素属性,并把属性作为参数传递个测试方法,两桶不同的写法 1. @DataProvider public Iterator<Object[]> dp() { mySleep(500 ...
- python高级编程:有用的设计模式1
# -*- coding: utf-8 -*-__author__ = 'Administrator'#python高级编程:有用的设计模式#设计械是可复用的,某种程序上它对软件设计中觉问题提供的语言 ...
- bootstrap学习以及其插件
Bootstrap中文网地址,里面有bootstrap组件的下载与使用说明,现在使用bootstrap3: http://www.bootcss.com/ W3CSchool.CC里面有学习boots ...
- 解决vsftpd 530 Permission denied报错
虚拟机装好RedHat后,准备使用filezilla连接,输入IP地址,root用户,密码,快速连接,报错: 故障排除: 1.首先检查系统是否开启了vsftp服务,如果没有开启,先开启该服务. 方法1 ...
- <经验杂谈>C#中一种最简单、最基本的反射(Reflection):通过反射获取方法函数
说起反射之前和很多用C#/.net的同仁们一样,相比于一般应用层对数据的增删改查总有点觉得深奥到难以理解.其实程序这东西,用过.实践过就很简单,我一直这么认为. 先说下概念:反射 Reflection ...
- JS高级程序设计学习笔记之Date类型
日期对象的创建:var now =new Date(),不传递参数时,对象自动获取当前时间.(若要创建特定日期与时间的对象,必须传入该日期距离1970/1/1零点的毫秒数). Date.parse() ...
- F# 天生就是就异步和并行的料
做模型开发免不了要使用异步和并行计算,尤其在多核CPU的今天,更是如此,F#恰逢其时,天生就具备这种能力,先看一个例子. open System open System.Drawing open Sy ...