/*
* =====================================================================================
*
* Filename: phpServer.cpp
* Version: 0.1
* Created: 2011年05月16日 07时40分56秒
* Compiler: g++
*
* Author: zhxm,501205289@qq.com
* Company: xd-1301
*
* =====================================================================================
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<strings.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include <string>
#include <memory.h>
#include <iostream>
using namespace std;
//缓冲区大小
#define MAX_BUF_SIZE 1024*1024
//分段发送函数
int mySend(void* buf,int size,int sockfd)
{
int sended=0;
while(1)
{
int flag = send(sockfd, (char*)buf+sended,size-sended,0);
if(flag ==-1)//发送失败
{
//重新试一试
flag = send(sockfd, (char*)buf+sended,size-sended,0);
if(flag == -1)//如果还是失败,则放弃发送
break;
}
sended +=flag;
if(sended>=size)
{
break;
}
}
return sended;
}
//返回 PHP-cgi消息的头和内容的分界点
//php-cgi处理php的返回消息格式如下
//head \r\n
//\r\n
//content \r\n
char* dealPHPMes(char* data,int len)
{
char* p = data;
char* end = p+len-3;
for(;p<end;p++)//两个\r\n的地方就是头和内容的分界
{
if(*p=='\r' && *(p+1) =='\n' && *(p+2)=='\r' && *(p+3)=='\n')
return p+4;
}
return data;
}
//从http请求头中获取请求的文件
//http典型请求头如下:
//GET /a.php?a=10&b=10 HTTP/1.1 \r\n
//
//函数返回./a.php
string getReq(char* buf,int len)
{
string temp = ".";
char *p=buf;
char* end = buf+len;
for(;p<end;p++)
if(*p=='/') break;
for(;p<end;p++)
{
//空格 或者\r\n是典型的结束符号
if(*p=='?' || *p == ' ') break;
temp +=*p;
}
return temp;
}
//从http请求头中获取请求的文件的类型
//http典型请求头如下:
//GET /a.php?a=10&b=10 HTTP/1.1 \r\n
//
//函数返回"php"
string getType(char* buf,int len)
{
string temp = "";
char *p=buf;
char* end = buf+len;
for(;p<end;p++)
if(*p=='.') break;
for(p++;p<end;p++)
{
if(*p=='?' || *p==' ') break;
temp +=*p;
}
return temp;
}
//从http请求头中获取请求的参数
//http典型请求头如下:
//GET /a.php?a=10&b=10 HTTP/1.1 \r\n
//
//函数返回"a=10 b=10"
string getArg(char* buf,int len)
{
string temp = "";
string method;
char tempBuf[10];
char *p=buf;
char* end = buf+len;
sscanf(buf,"%s",tempBuf);
method=tempBuf;
if(method=="GET")//只考虑GET POST 两种方法 GET方法参数紧跟请求文件后面 如a.php?a=10&b=10
{
for(;p<end;p++)
if(*p=='?') break;//'?'是参数列表的开始符号
for(p++;p<end-1;p++)
{
if(*p=='\r' && *(p+1)=='\n') break;
if(*p==' ')break;
if(*p=='&')//a=10&b=10 转成a=10 b=10
temp +=' ';
else
temp += *p;
}
return temp;
}
else if(method=="POST")//POST方法,参数放在了数据包里面,而不在http头。“\r\n\r\n”后面紧跟着就是数据包
{
for(;p<end;p++)//定位到头和数据包的分界
{
if(*p=='\r' && *(p+1) =='\n' && *(p+2)=='\r' && *(p+3)=='\n')
break;
}
// printf("%s",p);
for(p=p+4;p<end;p++)//解析数据包
{
if(*p=='\r' && *(p+1)=='\n') break;
if(*p==' ')break;
if(*p=='&')
temp +=' ';
else
temp += *p;
}
// cout<<temp;
return temp;
}
else
return " ";
}
//服务程序
int PHPServer()
{
int sockfd, client_fd;
struct sockaddr_in server;
struct sockaddr_in client;
socklen_t sin_size;
char buf[MAX_BUF_SIZE];
pid_t pid;
int flag;
if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("socket() error.");
return -1;
}
// pid = getpid();
pid=80;//监听80端口
bzero(&server, sizeof(server));
server.sin_family = AF_INET;
server.sin_port = htons(pid);
server.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockfd, (struct sockaddr *)&server, sizeof(server)) == -1)
{
printf("bind() error.");
return -1;
}
if(listen(sockfd,5) == -1)
{
printf("listen() error.");
return -1;
}
printf("listening %d\n",pid);
sin_size = sizeof(struct sockaddr_in);
while(1)
{
if((client_fd = accept(sockfd, (struct sockaddr *)&client, &sin_size )) == -1)//接受客户端请求
{
perror("accept() error.");
exit(1);
}
memset(buf,0,MAX_BUF_SIZE);
int len = recv(client_fd,buf,MAX_BUF_SIZE,0); //接收请求头
string type=getType(buf,len);//获取请求类型
string req = getReq(buf,len);//获取请求文件对象
string arg=getArg(buf,len);//获取参数
string contentType;
// cout<<"type:"<<type<<endl;
if(type=="png")//不同的请求类型,对应不同的应答类型 PS:这里应该用数据驱动的,为了方便,就没有用数据驱动了。
contentType="image/png";
else if(type=="jpeg" || type == "jpg")
contentType = "image/jpeg";
else if(type=="json" )
contentType = "application/json";
else if(type=="gif")
contentType = "image/gif";
else if(type=="html" || type=="htm")
contentType="text/html";
else if(type=="php")
contentType = "text/html";
else if(type=="js")
contentType = "application/x-javascript";
else if(type=="css")
contentType = "text/css";
else
contentType = "text/html";
memset(buf,0,MAX_BUF_SIZE);
//封装应答头 时间等字段先不考虑
sprintf(buf,"HTTP/1.1 200 OK \r\nDate: Sat, 14 May 2011 14:10:15 GMT\r\nExpires: Sat, 14 May 2011 14:14:45 GMT\r\nCache-Control: private, max-age=31536000\r\nX-Content-Type-Options: nosniff\r\nServer: sffe\r\nContent-Type: %s\r\n",contentType.c_str());
int bufLen = strlen(buf);
if(type=="php")//单独处理php请求
{
char cmd[1024]={0};
cout<<"req:"<<req<<endl;
//方便起见,直接用系统调用实现php解析。实际当中用的是fastcgi。
//系统调用的实例:php-cgi a.php a=10 b=20
//php解析后的结果存到temp文件中
sprintf(cmd,"php-cgi %s %s >> temp",req.c_str(),arg.c_str());
system(cmd);
char phpContext[1024*1024]={0};
FILE* f=fopen("temp","r");//从temp文件中获取结果
len = fread(phpContext,1,MAX_BUF_SIZE,f);
fclose(f);
//处理请求结果
char* content = dealPHPMes(phpContext,len);
//向http头追加内容长度
int lena= sprintf(buf+bufLen,"Content-Length: %d\r\n",strlen(content));
bufLen +=lena;
//然后追加真正的处理结果
lena = sprintf(buf+bufLen,"%s",phpContext);
bufLen += lena;
system("rm temp");
}
else //非php请求都当成普通文件处理
{
FILE* f=fopen(req.c_str(),"rb");//打开请求的文件
if(f==NULL)
{
string defPage="<html><b><center>404 n
- 1
- 2
- 3
前往页