zoukankan      html  css  js  c++  java
  • (转)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!
    ";  
    echo $_SERVER['MY_NAME']."
    ";  
    

     

    其中$_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 != ''){
    
    *bodyBuffPtr++ = *name++;
    
    }
    
    while(*value != ''){
    
    *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
    ",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,"
    endRequest:appStatus:%d,protocolStatus:%d
    ",(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.14  
      
    Content-type: text/html  
      
    Hollo World!  
      
    laiwenhui  
      
    endRequest:appStatus:0,protocolStatus:0 

     转载自ITCoder

    原文链接:http://www.itcoder.me/?p=250

  • 相关阅读:
    hihoCoder week20 线段树的区间修改
    hihoCoder week19 RMQ问题再临-线段树 单点更新 区间查询
    hihoCoder week17 最近公共祖先·三 lca st表
    hihoCoder week16 RMQ-ST算法
    hihoCoder week15 最近公共祖先·二
    eclipse 分屏显示同一文件
    eclipse 每次以debug方式启动springboot之后都会在SilentExitExceptionHandler类中的throw new SilentExitException()处断开,但是我明明没有下断点啊
    eclipse alt+/智能提示错误问题
    SpringBoot 之 普通类获取Spring容器中的bean
    kafka常用命令
  • 原文地址:https://www.cnblogs.com/fengwei/p/3641859.html
Copyright © 2011-2022 走看看