服务器开发之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;
}
根据上个章节描述的可执行文件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;
}
相关文章推荐
- 网络游戏服务器开发::学习了两天python写了一个linux下自动安装程序的脚本
- Linux网络编程学习笔记(5)---实现点对点通信(回射客服端/服务器模型)
- 【嵌入式Linux学习七步曲之第七篇 Linux的高级应用编程】网络编程中并发服务器的设计模式
- Linux网络编程-简单的客户端和服务器通讯程序开发入门(2)
- Linux网络编程--9. 服务器模型
- 学习Linux网络编程
- Linux网络编程一步一步学-自己编写一个HTTP协议的目录浏览和文件下载服务器
- Proxy源代码分析--谈谈如何学习linux网络编程
- 【嵌入式Linux学习七步曲之第二篇 交叉开发环境】SuSe11.1 上架设NFS服务器
- Proxy源代码分析--谈谈如何学习linux网络编程
- 网络游戏服务器开发:脚本系统的制作,linux下使用tolua制作Lua脚本系统(不需要PKG文件)
- (转)学习Linux编程开发必读书籍
- 《Web Service 编程 --用C#.NET 开发网络服务》北京希望出版社 我的学习笔记(第二章)(也就是书上抄了一写东西而已)
- 【嵌入式Linux学习七步曲之第二篇 交叉开发环境】FC6 上架设TFTP服务器,Transfer timed out
- Proxy源代码分析——谈谈如何学习Linux网络编程
- Linux网络编程一步一步学-编写一个HTTP协议的目录浏览和文件下载服务器
- Proxy源代码分析--谈谈如何学习linux网络编程
- Linux网络编程-服务器和客户机的信息函数(3)
- Linux网络编程:9. 服务器模型
- Linux网络编程:一个简单的正向代理服务器的实现