(轉)fastcgi協議的簡單實現

FastCgi不只能夠用於webserver與PHP的交互,也可用於任何兩個應用之間的交互,PHPer用的比較多的應該就是用於兩個子系統之間的交互。 好比A系統和B系統分部獨立的部署在兩臺機器上,其之間通訊用的比較多的http協議通訊,但經過fastcgi協議通訊能夠更加簡潔、高效。 下面將寫個的程序模擬webserver與PHP交互: 首先咱們看下webserver與fastcgi應用(如PHP)的交互過程:php

 

PHP $_SERVER數組中變量都是webserver經過FCGI_PARAMS傳遞到PHP的,關於fastcgi協議詳情請查看:fastcgi協議 下面的程序主要實現的是: 執行PHP所在機器/opt/data/www/index.php文件: Index.php文件的內容爲:html

 

echo "Hollo World!\n";  
echo $_SERVER['MY_NAME']."\n";  

 

其中$_SERVER['MY_NAME']是咱們經過程序傳遞過來的變量。 程序具體以下(只是簡單模擬交互,程序可能不完善): Fasctcgi.h:web

 
/*

* 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 */

  fastcgiredis

#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.14  
  
Content-type: text/html  
  
Hollo World!  
  
laiwenhui  
  
endRequest:appStatus:0,protocolStatus:0 

 

 轉載自ITCoderapp

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

相關文章
相關標籤/搜索