/*这份代码经源码格式软件格式化过 */
//servnet.c
/* 源程序 servnet.c */
#include<stdio.h>
#include<string.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<errno.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<sys/types.h>
unsigned short port=80 ;
char*error_return="<HTML>\n<BODY>File not found\n</BODY>\n</HTML>" ;
//当所请求的 HTML 文件不存在时返回该信息给浏览器
char ret_buf[32768];
char*envp[10];
//环境变量
char pathname[100];
//CGI 程序路径名
char cginame[20];
//CGI 程序名
char para[1024];
//CGI 参数
char*read_file(char*buf,int num_buf);
//该函数的功能是从 buf 中分离出绝对路径名,然后检验文件的合法性,然后读
//取文件中的数据,长度由 num_buf 决定,然后返回所独取得数据。
char*getcontentlen(char*buf);
//该函数的功能是从 buf 中读取 CGI 参数的长度并将之写入环境变量中。
20
char*getcontenttype(char*buf);
//该函数的功能是从 buf 中读取内容类型并将之写入环境变量中。
char*getpathname(char*buf,char*request);
//该函数的功能是从 buf 中读取 CGI 程序路径名,并将之存入相应的变量。
char*getcginame(char*pathname);
//该函数的功能是从 buf 中读取 CGI 程序名,并将之存入相应的变量。
char*getparaments(char*buf);
//该函数的功能是从 buf 中读取 CGI 参数,并将之存入相应的变量。
int main(int argc,char*argv[])
{
int i,acc_sock ;
//acc_sock 为连接套接子
char*recvBuffer=(char*)malloc(4001);
//服务器端接收缓冲区
int rc=0 ;
int serverSocket ;
struct sockaddr_in serverAddr ;
struct sockaddr_in clientAddr ;
int clientAddrSize ;
struct hostent*entity ;
int totalReceived ;
int size ;
int totalSent ;
int bytesSent ;
int pid2 ;
int fd1[2],fd2[2];
//pipe: fd[0] read,fd[1] write
char*cbuf ;
char request[5];
//设置环境变量的初始值
envp[0]=(char*)malloc(sizeof(char)*50);
strcpy(envp[0],"CONTENT_TYPE=application/x-www-form-urlencoded");
envp[1]=(char*)malloc(sizeof(char)*30);
strcpy(envp[1],"REQUEST_METHOD=POST");
envp[2]=(char*)malloc(sizeof(char)*30);
strcpy(envp[2],"CONTENT_LENGTH=38");
envp[3]=(char*)malloc(sizeof(char)*1024);
strcpy(envp[3],"QUERY_STRING=");
printf("initial over...........\n");
serverSocket=socket(AF_INET,SOCK_STREAM,0);
//建立 socket
if(serverSocket==-1)
{
printf("Invalid socket\n");
exit(1);
}
serverAddr.sin_family=AF_INET ;
serverAddr.sin_port=htons(port);
serverAddr.sin_addr.s_addr=htonl(INADDR_ANY);
memset(&(serverAddr.sin_zero),0,8);
printf("Binding server socket to port %d\n",port);
rc=bind(serverSocket,(struct sockaddr*)&serverAddr,sizeof(struct
sockaddr));
//绑定
if(rc==-1)
{
printf("Bad bind\n");
exit(1);
}
rc=listen(serverSocket,10);
//允许 10 个连接
if(rc==-1)
{
printf("Bad listen\n");
exit(1);
}
while(1)
{
printf("\nAccepting connections...\n");
clientAddrSize=sizeof(struct sockaddr_in);
//阻塞方式等待客户连接
acc_sock=accept(serverSocket,(struct
sockaddr*)&clientAddr,&clientAddrSize);
if(fork()==0)
{
if(acc_sock==-1)
{
printf("Bad accept\n");
exit(1);
}
}
entity=gethostbyaddr((char
*)&clientAddr.sin_addr,sizeof(struct in_addr),AF_INET);
printf("Connection from .........%s\n",inet_ntoa((struct
in_addr)clientAddr.sin_addr));
i=recv(acc_sock,recvBuffer,4000,0);
if(i==-1)
{
printf("recv error!\n");
exit(0);
}
recvBuffer[i]='\0' ;
printf("Received from client........%s\n",recvBuffer);
printf("*****************recvbuf display
end**********************\ n ");
/////////////////////////////////////////
//本服务器所有的 cgi 程序都放在一个 cgi-bin 文件夹中,因此通过判断接收缓
//冲区中的字符时不是包含 cgi-bin 来判断是否为 cgi 请求
if(strstr(recvBuffer,"cgi-bin")==NULL)
{
printf("$$this is not a CGI REQUEST!!\n");
//如果不是 cgi 请求,那么直接调用函数 read_file(),返回所请求的文件
cbuf=read_file(recvBuffer,totalReceived);
size=strlen(cbuf);
totalSent=0 ;
do
{
bytesSent=send(acc_sock,cbuf+totalSent,i=strlen(cbuf+totalSent),0);
if(bytesSent==-1)break ;
totalSent+=bytesSent ;
}
while(totalSent<size);
close(acc_sock);
}
else
{
printf("$$this is a CGI REQUEST!!\n");
getparaments(recvBuffer);
getcontentlen(recvBuffer);
//
getcontenttype(recvBuffer);
//
request[4]='\0' ;
printf("step1\n");
strncpy(request,recvBuffer,4);
printf("request :|%s|\n",request);
getpathname(recvBuffer,request);
getcginame(pathname);
if(pipe(fd1)<0||pipe(fd2)<0)
printf("pipe error\n");
if((pid2=fork())<0)
printf("fork error\n");
if(pid2>0)
{
close(fd1[0]);
close(fd2[1]);
if(!strcmp(request,"POST"))
//如果是 POST 方法,那么通过写管道 fd1[1],将参数由标准输入传给 CGI 程序
write(fd1[1],para,strlen(para));
else
{
strcpy(envp[3],"QUERY_STRING=");
//如果是 GET 方法,那么通过设置环境变量传递参数
strcat(envp[3],para);
}
//等待子进程结束
printf("$waiting for cgi's respond..........");
waitpid(pid2,NULL,0);
printf("child pid:%d finished!\n",pid2);
//从管道 fd2[0]读取 cgi 程序的返回结果
i=read(fd2[0],ret_buf,32768);
if(i==0)
{
printf(" read 0\n");
exit(1);
}
ret_buf[i]='\0' ;
//将取得的返回结果发送给浏览器
cbuf=ret_buf ;
size=strlen(cbuf);
totalSent=0 ;
do
{
bytesSent=send(acc_sock,cbuf+totalSent,i=strlen(cbuf+totalSent),0);
if(bytesSent==-1)break ;
totalSent+=bytesSent ;
}
while(totalSent<size);
close(acc_sock);
}
else
{
close(fd1[1]);
close(fd2[0]);
printf("$cgi handling.........\n");
if(fd1[0]!=STDIN_FILENO)
//重定向子进程的标准输入到 fd1[0]
if(dup2(fd1[0],STDIN_FILENO)!=STDIN_FILENO)
printf("dup2 error\n");
if(fd2[1]!=STDOUT_FILENO)
//重定向子进程的标准输出到 fd2[1]
if(dup2(fd2[1],STDOUT_FILENO)!=STDOUT_FILENO)
printf("dupe error\n");
//装入 cgi 程序,传递环境变量,并运行
execle(pathname,cginame,(char*)0,envp);
}
//end else
}
//end else
close(acc_sock);
exit(0);
}
close(acc_sock);
}
//end while
}
//end main
char*read_file(char*buf,int num_buf)
{
int i ;
char*cp,*cp2 ;
FILE*f ;
cp=buf+5 ;
cp2=strstr(cp," HTTP");
//使 cp2 指向路径名尾
if(cp2!=NULL)*cp2='\0' ;
//此时 cp 中存的即为浏览器所请求的文
件 路 径 名
printf("$$$file: |%s|\n",cp);
f=fopen(cp,"r");
//只读方式打开文件
if(f==NULL)
{
- 1
- 2
- 3
前往页