利用xinetd实现简单web服务器(镜像站)
2017-10-22 17:14
239 查看
浏览效果:
![](http://img.blog.csdn.net/20171022171420033?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ29uZ2x1Y2s5Mw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
linux服务器安装xinetd后,在/etc/xinetd.d/目录下创建xhttpd文件,并输入内容:
service xhttpd
{
socket_type = stream
protocol = tcp
wait = no
user = gongluck
server = /home/gongluck/桌面/xhttpd
server_args = /home/gongluck/桌面/xhttpdir
disable = no
flags = IPv4
}然后在/etc/services文件的最后添加自己使用的端口和进程的名字:
xhttpd 9527/tcp # xhttpd service
xhttpd 9527/udp # xhttpd servic重启服务:
sudo service xinetd restartxhttpd程序的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <dirent.h>
#define LEN 4096
char* get_filetype(const char* file);
void send_error(int status,char* title);
void send_header(int status,char* title, char* filetype);
void decode(char* to, char* from);
void encode(char* to, char* from);
int main(int argc,const char* argv[])
{
if(argc < 2)
send_error(500,"server error : argc < 2");
//if(access(argv[1],R_OK | F_OK) != 0)
if(chdir(argv[1]) < 0)
send_error(500,"server error : chdir error");
char line[LEN],type[LEN],path[LEN],protocol[LEN];
if(fgets(line,sizeof(line),stdin) == NULL)
send_error(500,"server error : type path protocol");
if(sscanf(line,"%[^ ] %[^ ] %[^ ]",type,path,protocol) != 3)
send_error(400,"bad request");
if(strcasecmp(type,"GET") != 0)
send_error(400,"method not allow");
if(path[0] != '/')
send_error(404,"file not found");
while(fgets(line,sizeof(line),stdin) != NULL)
{
if(strcmp(line,"\n") == 0 || strcmp(line,"\r\n") == 0)
break;
}
char file[LEN];
struct stat st;
file[0] = '.';
decode(file+1,path);
//printf("%s\n",&path[1]);
//printf("%s\n",file);
if(stat(file,&st) < 0)
{
printf("file : %s\r\n",file);
send_error(500,"server error : stat");
}
if(S_ISDIR(st.st_mode))
{
send_header(200,"OK","text/html;charset=utf-8");
printf("<html>"
"<head><title>Index of %s</title></head>"
"<body bgcolor=\"#cc99cc\">"
"<h4>Index of %s</h4>"
"<pre>"
,file,file);
struct dirent** dl;
int nf = scandir(file,&dl,NULL,alphasort);
if(nf < 0)
perror("scandir");
else
{
struct stat fst;
char stfile[LEN];
for(int i=0;i<nf; ++i)
{
strcpy(stfile,file);
strcat(stfile,"/");
strcat(stfile,dl[i]->d_name);
if(lstat(stfile,&fst) < 0)
printf("<a href=\"%s%s/\">%-32.32s/</a>",file+1,dl[i]->d_name,dl[i]->d_name);
else if(S_ISDIR(fst.st_mode))
printf("<a href=\"%s%s/\">%-32.32s/</a> \t\t%14lld",file+1,dl[i]->d_name,dl[i]->d_name,(long long)fst.st_size);
else
printf("<a href=\"%s%s\">%-32.32s</a> \t\t%14lld",file+1,dl[i]->d_name,dl[i]->d_name,(long long)fst.st_size);
printf("<br/>");
}
}
printf("</pre>"
"</body>"
"</html>");
}
else
{
//普通文件
FILE* fp = fopen(file,"r");
if(fp == NULL)
send_error(500,"server error : open file");
send_header(200,"send header",get_filetype(file));
int ch;//这里必须用int判断EOF,我真是菜鸡。
while((ch = getc(fp)) != EOF)
{
putchar(ch);
}
fflush(stdout);
fclose(fp);
fp = NULL;
}
// printf("test success !\n");
return 0;
}
int hex2d(char hex)
{
if(hex >= '0' && hex <= '9')
return hex-'0';
else if(hex >= 'a' && hex <= 'f')
return hex-'a'+10;
else if(hex >= 'A' && hex <= 'F')
return hex-'A'+10;
else
return hex;
}
void decode(char* to, char* from)
{
if(to == NULL || from == NULL)
return;
while(*from != '\0')
{
if(from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2]))
{
*to = hex2d(from[1])*16 + hex2d(from[2]);
from += 3;
}
else
{
*to = *from;
++from;
}
++to;
}
*to = '\0';
}
void encode(char* to, char* from)
{
if(to == NULL && from == NULL)
return;
while(*from != '\0')
{
if(isalnum(*from) || strchr("/._-~",*from) != NULL)
{
*to = *from;
++to;
++from;
}
else
{
sprintf(to,"%%%02x",*from);
to += 3;
from += 3;
}
}
*to = '\0';
}
char* get_filetype(const char* file)
{
if(file == NULL)
return NULL;
char* dot = strrchr(file,'.');
if(*dot == '\0')
return "text/plain; charset=utf-8";
else if(strcmp(dot,".html") == 0)
return "text/html; charset=utf-8";
else if(strcmp(dot, ".jpg") == 0)
return "image/jpeg";
else if(strcmp(dot, ".gif") == 0)
return "image/gif";
else if(strcmp(dot, ".png") == 0)
return "image/png";
else if(strcmp(dot, ".wav") == 0)
return "audio/wav";
else if(strcmp(dot, ".avi") == 0)
return "video/x-msvideo";
else if(strcmp(dot, ".mov") == 0)
return "video/quicktime";
else if(strcmp(dot, ".mp3") == 0)
return "audio/mpeg";
else
return "text/plain; charset=utf-8";
}
void send_header(int status, char* title, char* filetype)
{
if(title == NULL || filetype == NULL)
{
title = "ERROR";
filetype = "text/plain; charset=utf-8";
}
printf("HTTP/1.1 %d %s\r\n",status,title);
printf("Content-Type:%s\r\n",filetype);
printf("\r\n");
}
void send_error(int status,char* title)
{
if(title == NULL)
title = "ERROR";
send_header(status,title,"text/html; charset=utf-8");
printf("<html>\n"
"<head><title>%d %s</title></head>\n"
"<body bgcolor=\"#cc99cc\">\n"
"<h4>error!</h4>\n"
"<hr>\n"
"<address>\n"
"<a href=\"http://blog.csdn.net/gongluck93/\">gongluck</a>\n"
"</address>\n"
"</body>\n"
"</html>",
status,title);
fflush(stdout);
exit(1);
}由于xinetd会帮助我们与浏览器建立好连接,并且将stdin重定向到浏览器的发送端,stdout重定向到浏览器的接收端。所以xhttpd程序只需要从标准输入中读取浏览器的请求数据,把响应数据写入标准输出中即可。
这里只是用http协议的很简单的一部分:
GET /请求的文件名 HTTP/1.1
linux服务器安装xinetd后,在/etc/xinetd.d/目录下创建xhttpd文件,并输入内容:
service xhttpd
{
socket_type = stream
protocol = tcp
wait = no
user = gongluck
server = /home/gongluck/桌面/xhttpd
server_args = /home/gongluck/桌面/xhttpdir
disable = no
flags = IPv4
}然后在/etc/services文件的最后添加自己使用的端口和进程的名字:
xhttpd 9527/tcp # xhttpd service
xhttpd 9527/udp # xhttpd servic重启服务:
sudo service xinetd restartxhttpd程序的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctype.h>
#include <dirent.h>
#define LEN 4096
char* get_filetype(const char* file);
void send_error(int status,char* title);
void send_header(int status,char* title, char* filetype);
void decode(char* to, char* from);
void encode(char* to, char* from);
int main(int argc,const char* argv[])
{
if(argc < 2)
send_error(500,"server error : argc < 2");
//if(access(argv[1],R_OK | F_OK) != 0)
if(chdir(argv[1]) < 0)
send_error(500,"server error : chdir error");
char line[LEN],type[LEN],path[LEN],protocol[LEN];
if(fgets(line,sizeof(line),stdin) == NULL)
send_error(500,"server error : type path protocol");
if(sscanf(line,"%[^ ] %[^ ] %[^ ]",type,path,protocol) != 3)
send_error(400,"bad request");
if(strcasecmp(type,"GET") != 0)
send_error(400,"method not allow");
if(path[0] != '/')
send_error(404,"file not found");
while(fgets(line,sizeof(line),stdin) != NULL)
{
if(strcmp(line,"\n") == 0 || strcmp(line,"\r\n") == 0)
break;
}
char file[LEN];
struct stat st;
file[0] = '.';
decode(file+1,path);
//printf("%s\n",&path[1]);
//printf("%s\n",file);
if(stat(file,&st) < 0)
{
printf("file : %s\r\n",file);
send_error(500,"server error : stat");
}
if(S_ISDIR(st.st_mode))
{
send_header(200,"OK","text/html;charset=utf-8");
printf("<html>"
"<head><title>Index of %s</title></head>"
"<body bgcolor=\"#cc99cc\">"
"<h4>Index of %s</h4>"
"<pre>"
,file,file);
struct dirent** dl;
int nf = scandir(file,&dl,NULL,alphasort);
if(nf < 0)
perror("scandir");
else
{
struct stat fst;
char stfile[LEN];
for(int i=0;i<nf; ++i)
{
strcpy(stfile,file);
strcat(stfile,"/");
strcat(stfile,dl[i]->d_name);
if(lstat(stfile,&fst) < 0)
printf("<a href=\"%s%s/\">%-32.32s/</a>",file+1,dl[i]->d_name,dl[i]->d_name);
else if(S_ISDIR(fst.st_mode))
printf("<a href=\"%s%s/\">%-32.32s/</a> \t\t%14lld",file+1,dl[i]->d_name,dl[i]->d_name,(long long)fst.st_size);
else
printf("<a href=\"%s%s\">%-32.32s</a> \t\t%14lld",file+1,dl[i]->d_name,dl[i]->d_name,(long long)fst.st_size);
printf("<br/>");
}
}
printf("</pre>"
"</body>"
"</html>");
}
else
{
//普通文件
FILE* fp = fopen(file,"r");
if(fp == NULL)
send_error(500,"server error : open file");
send_header(200,"send header",get_filetype(file));
int ch;//这里必须用int判断EOF,我真是菜鸡。
while((ch = getc(fp)) != EOF)
{
putchar(ch);
}
fflush(stdout);
fclose(fp);
fp = NULL;
}
// printf("test success !\n");
return 0;
}
int hex2d(char hex)
{
if(hex >= '0' && hex <= '9')
return hex-'0';
else if(hex >= 'a' && hex <= 'f')
return hex-'a'+10;
else if(hex >= 'A' && hex <= 'F')
return hex-'A'+10;
else
return hex;
}
void decode(char* to, char* from)
{
if(to == NULL || from == NULL)
return;
while(*from != '\0')
{
if(from[0] == '%' && isxdigit(from[1]) && isxdigit(from[2]))
{
*to = hex2d(from[1])*16 + hex2d(from[2]);
from += 3;
}
else
{
*to = *from;
++from;
}
++to;
}
*to = '\0';
}
void encode(char* to, char* from)
{
if(to == NULL && from == NULL)
return;
while(*from != '\0')
{
if(isalnum(*from) || strchr("/._-~",*from) != NULL)
{
*to = *from;
++to;
++from;
}
else
{
sprintf(to,"%%%02x",*from);
to += 3;
from += 3;
}
}
*to = '\0';
}
char* get_filetype(const char* file)
{
if(file == NULL)
return NULL;
char* dot = strrchr(file,'.');
if(*dot == '\0')
return "text/plain; charset=utf-8";
else if(strcmp(dot,".html") == 0)
return "text/html; charset=utf-8";
else if(strcmp(dot, ".jpg") == 0)
return "image/jpeg";
else if(strcmp(dot, ".gif") == 0)
return "image/gif";
else if(strcmp(dot, ".png") == 0)
return "image/png";
else if(strcmp(dot, ".wav") == 0)
return "audio/wav";
else if(strcmp(dot, ".avi") == 0)
return "video/x-msvideo";
else if(strcmp(dot, ".mov") == 0)
return "video/quicktime";
else if(strcmp(dot, ".mp3") == 0)
return "audio/mpeg";
else
return "text/plain; charset=utf-8";
}
void send_header(int status, char* title, char* filetype)
{
if(title == NULL || filetype == NULL)
{
title = "ERROR";
filetype = "text/plain; charset=utf-8";
}
printf("HTTP/1.1 %d %s\r\n",status,title);
printf("Content-Type:%s\r\n",filetype);
printf("\r\n");
}
void send_error(int status,char* title)
{
if(title == NULL)
title = "ERROR";
send_header(status,title,"text/html; charset=utf-8");
printf("<html>\n"
"<head><title>%d %s</title></head>\n"
"<body bgcolor=\"#cc99cc\">\n"
"<h4>error!</h4>\n"
"<hr>\n"
"<address>\n"
"<a href=\"http://blog.csdn.net/gongluck93/\">gongluck</a>\n"
"</address>\n"
"</body>\n"
"</html>",
status,title);
fflush(stdout);
exit(1);
}由于xinetd会帮助我们与浏览器建立好连接,并且将stdin重定向到浏览器的发送端,stdout重定向到浏览器的接收端。所以xhttpd程序只需要从标准输入中读取浏览器的请求数据,把响应数据写入标准输出中即可。
这里只是用http协议的很简单的一部分:
GET /请求的文件名 HTTP/1.1
HTTP/1.1 状态码 描述 Content-Type:回传文件类型 \r\n 回传文件数据
相关文章推荐
- WEB服务器:利用python CGI实现简单的微信后台服务器
- 利用lvs-nat实现两台web服务器负载均衡的简单案例
- 利用python2.7自带的简单的web服务器SimpleHTTPServer实现web页面的访问
- 利用http协议实现一个简单的web服务器
- Go语言实现简单的web服务器
- 利用python自带的包可以建立简单的web服务器
- 【Web后端笔记】基于Socket实现的简单Web服务器搭建
- 利用WebRequest来实现模拟浏览器通过Post方式向服务器提交数据
- 使用HttpListener实现简单Web服务器
- Python实现简单的Web服务器
- docker学习笔记6:利用dockerfile创建镜像介绍(生成简单web服务器镜像)
- 用Java socket (TCP通信模型)实现一个简单的web 服务器
- Go语言实现简单的一个静态WEB服务器
- VS2005 Web项目安装部署:利用预编译的Dll 隐藏.cs文件 的简单实现
- Python实现简单的Web服务器 解析
- 利用 Nginx 负载均衡实现 Web 服务器更新不影响访问
- C#中使用Socket实现简单Web服务器
- C实现简单web服务器-1(windows)
- 用java 实现一个简单的web 服务器
- 利用WebBrowser实现Web新闻简单打印(个人小结)