您的位置:首页 > 理论基础 > 计算机网络

服务器开发之linux网络编程---学习章节(二)

2018-03-29 19:38 417 查看
前言:
        根据上个章节描述的可执行文件xhttpd的功能实现,这个篇章主要去描绘代码,并详细解释以下用到的相关库函数。
(源代码)#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define buf_size 4096
//发送HTTP的报头 HTTP/1.1 200 OK 回复文件的类型,文件的长度 以\r\n为结束符
void send_headers(char *response_client_data_type, off_t response_client_data_length)
//off_t = long long int
{
printf("%s %d %s\r\n","HTTP/1.1",200,"OK");
printf("Content-Type:%s\r\n",response_client_data_type);
// 确保文件长度的正确性!
printf("Content-Length:%lld\r\n",(int64_t)response_client_data_length);
printf("Content:close\r\n");
printf("\r\n");
}
//发送错误格式 状态码,错误标题,错误描述
void send_error(int error_num,char *error_name,char *error_description)
{
send_headers("text/html",-1);
printf("<html>\n");
printf("<title>\n");
printf("<head>\n");
printf("%d %s\n",error_num,error_name);
printf("</head>\n");
printf("</title>\n");
printf("<body bgcolor=\"#cc99cc\">\n");
printf("<h3>%d %s</h3>\n",error_num,error_name);
printf("<h5>%s</h5>\n",error_description);
printf("</body>\n");
printf("</html>\n");
fflush(stdout);
exit(1);
}
//传入两个参数
int main(int argc,char *argv[])
{
char command_line[buf_size];
char requeset_method[buf_size];
char requeset_path[buf_size];
char requeset_protocol[buf_size];//http 1.1
char *file;
struct stat sb;
FILE *fp;
int ich;
char *response_client_data_type;
if(argc != 2)
send_error(500,"internal error","config error-no dir!");
if(chdir(argv[1]) < 0)
send_error(501,"file path error","config can't find dir!");
//fgets是按行读取 GET /文件或目录 HTTP/1.1
if(fgets(command_line,sizeof(command_line),stdin) == NULL)
send_error(400,"!!!","!!!");
//解析读取到内容 请求方式 /文件或者目录 HTTP/1.1
if(sscanf(command_line,"%[^ ] %[^ ] %[^ ]",requeset_method,requeset_path,requeset_protocol) != 3)
send_error(401,"requeset protocol error","we can't unsterdend your requeset");
while(fgets(command_line,sizeof(command_line),stdin) != NULL)
if(strcmp(command_line,"\r\n") == 0 || strcmp(command_line,"\n") == 0)
break;
//strcasecmp 忽略大小写,比较字符串,这里我们只是处理了GET方式请求
if(strcasecmp("GET",requeset_method) != 0)
send_error(501,"requeset method error","please use right method requeset");
if(requeset_path[0] != '/')
send_error(502,"invalid path","unable to find the path accoding to the path");
//获得文件名字
file = requeset_path + 1;
//得到文件信息,并将其保存到buf结构中,是以地址参数形式传递给stat
if(stat(file,&sb) < 0)
send_error(404,"not found","file not found");
fp = fopen(file,"r");//打开文件
if(fp == NULL) {
send_error(403,"forbidden","file is protected");
}
//strrchr 是从后面想前查找第一次出现的位置----是为了判断文件类型
char *dot = strrchr(file,'.');
//判断文件的类型并发送报头
if(dot == NULL) {
response_client_data_type = "text/plain:charset=utf-8";
}else if(strcmp(dot,".html") == 0) {
response_client_data_type = "text/html:charset=utf-8";
}else if(strcmp(dot,".jpg") == 0) {
response_client_data_type = "image/jpeg";
}else if(strcmp(dot,".gif") == 0) {
response_client_data_type = "imaged/gif";
}else if(strcmp(dot,".png") == 0) {
response_client_data_type = "imaged/png";
}else if(strcmp(dot,".mp3") == 0) {
response_client_data_type = "audio/mp3";
}else if(strcmp(dot,".txt") == 0) {
response_client_data_type = "imaged/txt";
}else {
response_client_data_type = "text/plain:charset=iso-8859-1";
}
//这里一定确保文件的长度正确性
send_headers(response_client_data_type,sb.st_size);
//发送文件
while((ich = getc(fp)) != EOF)
putchar(ich);
fflush(stdout);
fclose(fp);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐