简单web服务器程序(配置文件读取端口)
来源:互联网 发布:下载枪林弹雨刷枪软件 编辑:程序博客网 时间:2024/06/06 13:05
#include<stdio.h>
#include<string.h>
#include<netinet/in.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<unistd.h>
#include<signal.h>
#include<errno.h>
#include <sys/types.h>
#include<string.h>
#include<netinet/in.h>
#include<stdlib.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<unistd.h>
#include<signal.h>
#include<errno.h>
#include <sys/types.h>
//全局宏
#define MAX_LINE 1024
#define MAX_LINE 1024
#define BUG 1
#ifdef BUG
#define DEBUG_PRINT0(str); printf(str);
#else
#define DEBUG_PRINT0(str);
#endif
#define DEBUG_PRINT0(str); printf(str);
#else
#define DEBUG_PRINT0(str);
#endif
int init(struct sockaddr_in* sin,int* lfd,int* port);
int error_page(int sock_fd);
int get_path(int cfd,char* path);
int write_page(int cfd,char* path);
static int configuration(int *port,char* path);
int error_page(int sock_fd);
int get_path(int cfd,char* path);
int write_page(int cfd,char* path);
static int configuration(int *port,char* path);
struct sockaddr_in sinaddr,cin;
socklen_t len=sizeof(cin);
int lfd,cfd,fd;
pid_t pid;
int sock_opt=1; //套接字选项
int port;
char path[MAX_LINE]; //文件路径缓冲区
struct stat statbuf; //文件状态结构
socklen_t len=sizeof(cin);
int lfd,cfd,fd;
pid_t pid;
int sock_opt=1; //套接字选项
int port;
char path[MAX_LINE]; //文件路径缓冲区
struct stat statbuf; //文件状态结构
int main(void)
{
signal(SIGCHLD,SIG_IGN); //安装信号处理函数
signal(SIGPIPE,SIG_IGN);
{
signal(SIGCHLD,SIG_IGN); //安装信号处理函数
signal(SIGPIPE,SIG_IGN);
printf("initializing ...\n");
if(init(&sinaddr,&lfd,&port)==-1) //初始化
{
DEBUG_PRINT0("error during initializing\n");
exit(1);
}
while(1)
{
DEBUG_PRINT0("waiting connection...\n");
{
DEBUG_PRINT0("error during initializing\n");
exit(1);
}
while(1)
{
DEBUG_PRINT0("waiting connection...\n");
cfd=accept(lfd,(struct sockaddr*)&cin,&len); //连接
if(cfd==-1)
{
perror("fail to accept");
exit(1);
}
printf("客户端###:%s\n ",inet_ntoa(cin.sin_addr));
pid=fork(); //创建子进程,用于并发处理请求
if(pid<0)
{
perror("fail to fork");
exit(1);
}else if(pid==0) //子进程,处理连接请求
{
close(lfd); //处理连接,关闭监听套接字
if(cfd==-1)
{
perror("fail to accept");
exit(1);
}
printf("客户端###:%s\n ",inet_ntoa(cin.sin_addr));
pid=fork(); //创建子进程,用于并发处理请求
if(pid<0)
{
perror("fail to fork");
exit(1);
}else if(pid==0) //子进程,处理连接请求
{
close(lfd); //处理连接,关闭监听套接字
//分析客户端发来的信息,得到请求文件的路径
if(get_path(cfd,path)==-1) ///////////////////
{
DEBUG_PRINT0("error during geting filepath\n");
exit(1);
}
if(get_path(cfd,path)==-1) ///////////////////
{
DEBUG_PRINT0("error during geting filepath\n");
exit(1);
}
if(stat(path,&statbuf)!=0) //得到文件的状态
{
perror("fail to get file status");
exit(1);
}
{
perror("fail to get file status");
exit(1);
}
//非普通文件
if(!S_ISREG(statbuf.st_mode))
{
if(error_page(cfd)==-1) //输出出错页面
{
DEBUG_PRINT0("error during writing error-page\n");
close(cfd);
exit(1);
}
close(cfd); //关闭连接套接字,连接结束
exit(0); //子程序正常退出
}
//如果是可执行文件,说明是一个CGI文件
if(statbuf.st_mode & S_IXOTH)
{
dup2(cfd,STDOUT_FILENO);
if(execl(path,path,NULL)==-1) //执行该CGI文件
{
perror("fail to exec");
exit(1);
}
}
//非CGI文件,则需要回送文件内容给客户端
if((fd=open(path,O_RDONLY))<0)
{
if(error_page(cfd)==-1)
{
DEBUG_PRINT0("error during writing error-page\n");
close(cfd);
exit(1);
}
close(cfd);
exit(0); //子进程退出
}
if(write_page(cfd,path)==-1)
{
DEBUG_PRINT0("error during writing page\n");
exit(1);
}
close(fd); //关闭文件
close(cfd);//关闭连接套接字,服务器主动关闭,表示数据传输完毕
exit(0); //子进程退出
}else //父进程,继续监听连接请求
close(cfd); //继续监听,关闭连接套接字
}//end of while(1)
close(cfd); //继续监听,关闭连接套接字
}//end of while(1)
return 0;
}//end of main
}//end of main
/*配置文件的格式端口“port: 8000",目录“root-path";冒号后面有个空格*/
static int configuration(int *port,char* path)//读取配置文件获取端口和服务器的根目录
{
int i;
FILE* fp;
char* p;
char buf[50]; //文件内容的缓冲
static int configuration(int *port,char* path)//读取配置文件获取端口和服务器的根目录
{
int i;
FILE* fp;
char* p;
char buf[50]; //文件内容的缓冲
fp=fopen("./config.ini","r");
if(fp==NULL)
{
perror("fail to open config.ini");
return -1;
}
if(fp==NULL)
{
perror("fail to open config.ini");
return -1;
}
while(fgets(buf,50,fp)!=NULL) //读取每行的内容
{
if(buf[strlen(buf)-1]!='\n') //判断文件格式
return -1;
else
buf[strlen(buf)-1]='\0'; //添加结束符
{
if(buf[strlen(buf)-1]!='\n') //判断文件格式
return -1;
else
buf[strlen(buf)-1]='\0'; //添加结束符
if(strstr(buf,"port")==buf) //寻找“port”字样,读取端口号
{
if((p=strchr(buf,':'))==NULL)
{
printf("config.ini expect ':'\n");
return -1;
}
*port=atoi(p+2); //跳过”:"和空格,得到端口号
if(*port<=0)
{
printf("error port\n");
return -1;
}
}else if(strstr(buf,"root-path")==buf) //得到根目录
{
if((p=strchr(buf,':'))==NULL)
{
printf("config.ini expect':'\n");
return -1;
}
{
if((p=strchr(buf,':'))==NULL)
{
printf("config.ini expect ':'\n");
return -1;
}
*port=atoi(p+2); //跳过”:"和空格,得到端口号
if(*port<=0)
{
printf("error port\n");
return -1;
}
}else if(strstr(buf,"root-path")==buf) //得到根目录
{
if((p=strchr(buf,':'))==NULL)
{
printf("config.ini expect':'\n");
return -1;
}
p++;
p++; //跳过‘:’
strcpy(path,p);
}else
{
printf("error in config.ini\n");
return -1;
}
p++; //跳过‘:’
strcpy(path,p);
}else
{
printf("error in config.ini\n");
return -1;
}
}
return 0;
}
return 0;
}
//初始化函数,读取配置文件,获得端口和根目录;创建监听套接字,并且绑定地址;使用套接字启动监听
int init(struct sockaddr_in * sin,int* lfd,int *port)
{
if(configuration(port,path)==-1)
{
printf("fail to get th port and path from configuration\n");
return -1;
}
*lfd=socket(PF_INET,SOCK_STREAM,0); //创建socket
sin->sin_family=PF_INET;
sin->sin_port=htons(*port);
inet_aton("192.168.1.213",&sin->sin_addr);
int init(struct sockaddr_in * sin,int* lfd,int *port)
{
if(configuration(port,path)==-1)
{
printf("fail to get th port and path from configuration\n");
return -1;
}
*lfd=socket(PF_INET,SOCK_STREAM,0); //创建socket
sin->sin_family=PF_INET;
sin->sin_port=htons(*port);
inet_aton("192.168.1.213",&sin->sin_addr);
setsockopt(*lfd,SOL_SOCKET,SO_REUSEADDR,&sock_opt,sizeof(sock_opt));
//绑定
if(bind(*lfd,(struct sockaddr*)sin,sizeof(*sin))==-1)
{
printf("bind error\n");
return -1;
}
if(listen(*lfd,100)==1) //监听
{
printf("listen error\n");
return -1;
}
if(bind(*lfd,(struct sockaddr*)sin,sizeof(*sin))==-1)
{
printf("bind error\n");
return -1;
}
if(listen(*lfd,100)==1) //监听
{
printf("listen error\n");
return -1;
}
return 0;
}
}
//分析所需文件的路径
int get_path(int cfd,char *path)
{
char buf[MAX_LINE];
if(read(cfd,buf,MAX_LINE)==-1) //读取http协议
return -1;
int get_path(int cfd,char *path)
{
char buf[MAX_LINE];
if(read(cfd,buf,MAX_LINE)==-1) //读取http协议
return -1;
//http协议头第一行的格式为:"GET / HTTP/1.1"
if(strstr(buf,"GET")!=buf)
{
DEBUG_PRINT0("wrong request\n");
return -1;
}
if(strstr(buf,"GET")!=buf)
{
DEBUG_PRINT0("wrong request\n");
return -1;
}
if((buf[4]=='/') && (buf[5]==' ')) //没有指定文件名,使用默认文件“index.html"
strcat(path,"/index.html");
else{
strtok(&buf[4]," "); //否则使用客户端指定的文件名
strcat(path,&buf[4]);
}
return 0;
}
strcat(path,"/index.html");
else{
strtok(&buf[4]," "); //否则使用客户端指定的文件名
strcat(path,&buf[4]);
}
return 0;
}
//error_page函数向客户端输出一个出错的页面,这个页面包含出错信息,用来调试
int error_page(int sock_fd)
{
char err_str[1024];
int error_page(int sock_fd)
{
char err_str[1024];
#ifdef DEBUG
sprintf(err_str,"http/1.1 404 %s\r\n",strerror(errno.h));
#else
sprintf(err_str,"HTTP/1.1 404 Not Exsit\r\n");
#endif
sprintf(err_str,"http/1.1 404 %s\r\n",strerror(errno.h));
#else
sprintf(err_str,"HTTP/1.1 404 Not Exsit\r\n");
#endif
if(write(sock_fd,err_str,strlen(err_str))==-1)
return -1;
return -1;
return 0;
}
}
//write_page函数将需要的文件内容发送给客户端
int write_page(int cfd,char* path)
{
int n;
char buf[MAX_LINE];
int write_page(int cfd,char* path)
{
int n;
char buf[MAX_LINE];
//协议头格式输出
if(write(cfd,"HTTP/1.1 200 OK\r\n",strlen("HTTP/1.1 200 OK\r\n"))==-1)
return -1;
if(write(cfd,"HTTP/1.1 200 OK\r\n",strlen("HTTP/1.1 200 OK\r\n"))==-1)
return -1;
//页面的类型,则需要根据文件的扩展名来判断
if(write(cfd,"Content-Type: ",strlen("Content-Type: "))==-1)
return -1;
if(write(cfd,"Content-Type: ",strlen("Content-Type: "))==-1)
return -1;
n=strlen(path);
//三种图片格式,表示图片类型
if(strcasecmp(&path[n-3],"jpg")==0 || strcasecmp(&path[n-4],"jpeg")==0)
if(write(cfd,"image/jpeg",strlen("image/jpeg"))==-1)
return -1;
else if(strcasecmp(&path[n-3],"gif")==0)
if(write(cfd,"image/gif",strlen("image/gif"))==-1)
return -1;
else if(strcasecmp(&path[n-3],"png")==0)
if(write(cfd,"image/png",strlen("image/png"))==-1)
return -1;
else //纯文本类型
if(write(cfd,"text/html",strlen("text/html"))==-1)
return -1;
//三种图片格式,表示图片类型
if(strcasecmp(&path[n-3],"jpg")==0 || strcasecmp(&path[n-4],"jpeg")==0)
if(write(cfd,"image/jpeg",strlen("image/jpeg"))==-1)
return -1;
else if(strcasecmp(&path[n-3],"gif")==0)
if(write(cfd,"image/gif",strlen("image/gif"))==-1)
return -1;
else if(strcasecmp(&path[n-3],"png")==0)
if(write(cfd,"image/png",strlen("image/png"))==-1)
return -1;
else //纯文本类型
if(write(cfd,"text/html",strlen("text/html"))==-1)
return -1;
if(write(cfd,"\r\n\r\n",4)==-1) //添加协议结尾,最后多出一个”\r\n"
return -1;
return -1;
while((n=read(fd,buf,MAX_LINE))>0)
write(cfd,buf,n);
write(cfd,buf,n);
return 0;
}
}
0 0
- 简单web服务器程序(配置文件读取端口)
- web工程中在非servlet程序中读取配置文件
- 一个简单的Web服务器程序(java实现)
- java服务器读取配置文件
- java web 读取配置文件
- web.config配置文件读取
- linux下读取简单文本配置文件C程序
- 读取properties配置文件(简单版)
- 读取配置文件,简单代码
- 读取配置文件简单方法
- Java中Web程序修改配置文件不重启服务器的方法
- Web服务器常用端口
- WEB项目加载配置文件并读取配置文件
- WEB应用中读取配置文件
- WEB应用中读取配置文件
- Web应用中读取配置文件
- Web读取配置文件得到数据库连接
- Silverlight读取Web.config配置文件
- usb 问题
- Unity3D游戏开发之MMD For Unity插件研究
- linux route命令使用
- 黑马程序员——java基础知识
- 格局君谈创业
- 简单web服务器程序(配置文件读取端口)
- Debug与Trace的区别?//作者:西西
- 【Java基础】Hibernate之360度环视
- 看数据结构写代码(56) 平衡二叉树(AVL树)
- 2015上海●全球零售自有品牌产品亚洲展
- 相位匹配实验
- Android shape样式
- OpenSessionInViewFilter
- 国际专家齐聚申城,助力中国制造2025