(转)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 ...
随机推荐
- java进阶计划
鉴于自己在java 的学习过程中,像是无头苍蝇一样,东扎一把,西戳一下,没有一个明确的方向,也没有一个比较明确的方面,所以有了这个大致的计划. 计划的目标: 1. java本身的目标 对线程(thre ...
- hdu5014:number sequence对称思想
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5014 题目大意:给定数组 a[]={0,1,2......n} 求一个数组b[] 元素也为0.... ...
- python3-day4(yield)
1.yield 迭代器是访问集合元素的一种方式.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束.迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退.另外,迭代器的一 ...
- [RxJS] Completing a Stream with TakeWhile
Subscribe can take three params: subscribe( (x)=> console.log(x), err=> console.log(err), ()=& ...
- World Wind Java开发之十五——载入三维模型
之前的一篇博客是关于载入粗三维模型的,见http://blog.csdn.net/giser_whu/article/details/43452703,这个地方还存在着不能载入纹理的问题,一直没呢解决 ...
- MDM 证书申请流程(vendor及customer)
整个流程分为两部分:vendor,customer. 一.Vendor 1.成为一个 MDM Vendor 1) 首先你须要拥有一个 Apple Enterprise account($299/年). ...
- LVM管理
一.步骤: 1.创建新的分区,并修改分区类型为8e 2.创建物理卷PV 3.将新建的PV添加到要扩展的VG中 4.用命令lvextend或lvresize来将新加入的PE添加到要扩展的LV中 5.用命 ...
- Python进阶之路---1.3python环境搭建
python环境安装 windows python环境安装 下载安装包 https://www.python.org/downloads/ 安装并指定安装目录 C:\python2 ...
- IOS6和IOS7的屏幕适配问题
自从IOS7出来以后,以前写在IOS6上或者更低版本的程序,跑在IOS7的模拟器上就会出现一些问题.最大的问题就是,所有的UI空间都会统一向上移动20个点(如果空间的y值为0,就会被StatusBar ...
- <经验杂谈>C#/.Net字符串操作方法小结
字符串操作是C#中最基本的.最常见的.也是用的最多的,以下我总结 了几种常见的方法 1.把字符串按照分隔符转换成 List /// <summary> /// 把字符串按照分隔符转换成 L ...