1 可以掌握的知识点

(1) 线上部署时的守护应用

(2) 常规的文件操作,配置文件读取

(3) 网络编程,端口复用等文件

(4) 多进程知识

2 代码注释如下

test_httpd.h

 #include <pwd.h>
#include <grp.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/syslog.h>
#include <stdarg.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <resolv.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <signal.h>
#include <getopt.h>
#include <net/if.h>
#include <sys/ioctl.h> #define MAXBUF 1024
#define MAXPATH 128 char buffer[MAXBUF + ];
char ip[];//存储字符串形式的Ip地址
char port[];//存储字符串形式的端口
char back[];//listen队列大小
char home_dir[];//浏览主目录 void wrtinfomsg(char *msg)
{
syslog(LOG_INFO,"%s",msg);
} //读取配置文件
int get_arg (char *cmd)
{ FILE* fp;
char buffer[];
size_t bytes_read;
char* match;
fp = fopen ("/etc/test_httpd.conf", "r");
bytes_read = fread (buffer, , sizeof (buffer), fp);
fclose (fp); if (bytes_read == || bytes_read == sizeof (buffer))
return ;
buffer[bytes_read] = '\0'; //根据配置文件key得到value
if(!strncmp(cmd,"home_dir",))
{
match = strstr (buffer, "home_dir=");
if (match == NULL)
return ;
bytes_read=sscanf(match,"home_dir=%s",home_dir);
return bytes_read;
} else if(!strncmp(cmd,"port",))
{
match = strstr (buffer, "port=");
if (match == NULL)
return ;
bytes_read=sscanf(match,"port=%s",port);
return bytes_read;
} else if(!strncmp(cmd,"ip",))
{
match = strstr (buffer, "ip=");
if (match == NULL)
return ;
bytes_read=sscanf(match,"ip=%s",ip);
return bytes_read;
}
else if(!strncmp(cmd,"back",))
{
match = strstr (buffer, "back=");
if (match == NULL)
return ;
bytes_read=sscanf(match,"back=%s",back);
return bytes_read;
}
else
return ;
} //文件类型的判断
char file_type(mode_t st_mode)
{
if ((st_mode & S_IFMT) == S_IFSOCK)
return 's';
else if ((st_mode & S_IFMT) == S_IFLNK)
return 'l';
else if ((st_mode & S_IFMT) == S_IFREG)
return '-';
else if ((st_mode & S_IFMT) == S_IFBLK)
return 'b';
else if ((st_mode & S_IFMT) == S_IFCHR)
return 'c';
else if ((st_mode & S_IFMT) == S_IFIFO)
return 'p';
else
return 'd';
} //search the up-path of dirpath
char *dir_up(char *dirpath)
{
static char Path[MAXPATH];
int len; strcpy(Path, dirpath);
len = strlen(Path);
if (len > && Path[len - ] == '/')
len--;
while (Path[len - ] != '/' && len > )
len--;
Path[len] = ;
return Path;
} //如果路径是文件 就将文件的内容发送过去 如果是目录则列出目录文件
void GiveResponse(FILE * client_sock, char *Path)
{
struct dirent *dirent;
struct stat info;
char Filename[MAXPATH];
DIR *dir;
int fd, len, ret;
char *p, *realPath, *realFilename, *nport; struct passwd *p_passwd;
struct group *p_group;
char *p_time; //get th dir or file
len = strlen(home_dir) + strlen(Path) + ;
realPath = malloc(len + );
bzero(realPath, len + );
sprintf(realPath, "%s/%s", home_dir, Path);//获取文件的绝对路径 //get port
len = strlen(port) + ;
nport = malloc(len + );
bzero(nport, len + );
sprintf(nport, ":%s", port);//存储端口信息 //获取文件属性
if (stat(realPath, &info)) {
//获取失败 输出这样信息 这信息格式满足http协议
fprintf(client_sock,
"HTTP/1.1 200 OK\r\nServer:Test http server\r\nConnection: close\r\n\r\n<html><head><title>%d - %s</title></head>"
"<body><font size=+4>Linux HTTP server</font><br><hr width=\"100%%\"><br><center>"
"<table border cols=3 width=\"100%%\">", errno,
strerror(errno));
fprintf(client_sock,
"</table><font color=\"CC0000\" size=+2> connect to administrator, error code is: \n%s %s</font></body></html>",
Path, strerror(errno));
goto out;
} //如果是文件则下载
if (S_ISREG(info.st_mode))
{
fd = open(realPath, O_RDONLY);
len = lseek(fd, , SEEK_END);
p = (char *) malloc(len + );
bzero(p, len + );
lseek(fd, , SEEK_SET);
//这里是一次性读取 小文件
ret = read(fd, p, len);
close(fd);
fprintf(client_sock,
"HTTP/1.1 200 OK\r\nServer: Test http server\r\nConnection: keep-alive\r\nContent-type: application/*\r\nContent-Length:%d\r\n\r\n", len); fwrite(p, len, , client_sock);
free(p);
}
else if (S_ISDIR(info.st_mode))
{ //列出目录
dir = opendir(realPath);
fprintf(client_sock,
"HTTP/1.1 200 OK\r\nServer:Test http server\r\nConnection:close\r\n\r\n<html><head><title>%s</title></head>"
"<body><font size=+4>Linux HTTP server file</font><br><hr width=\"100%%\"><br><center>"
"<table border cols=3 width=\"100%%\">", Path);
fprintf(client_sock,
"<caption><font size=+3> Directory %s</font></caption>\n",
Path);
fprintf(client_sock,
"<tr><td>name</td><td>type</td><td>owner</td><td>group</td><td>size</td><td>modify time</td></tr>\n");
if (dir == NULL) {
fprintf(client_sock, "</table><font color=\"CC0000\" size=+2>%s</font></body></html>",
strerror(errno));
return;
}
while ((dirent = readdir(dir)) != NULL)
{
if (strcmp(Path, "/") == )
sprintf(Filename, "/%s", dirent->d_name);
else
sprintf(Filename, "%s/%s", Path, dirent->d_name);
if(dirent->d_name[]=='.')
continue;
fprintf(client_sock, "<tr>");
len = strlen(home_dir) + strlen(Filename) + ;
realFilename = malloc(len + );
bzero(realFilename, len + );
sprintf(realFilename, "%s/%s", home_dir, Filename);
if (stat(realFilename, &info) == )
{
if (strcmp(dirent->d_name, "..") == )
fprintf(client_sock, "<td><a href=\"http://%s%s%s\">(parent)</a></td>",
ip, atoi(port) == ? "" : nport,dir_up(Path));
else
fprintf(client_sock, "<td><a href=\"http://%s%s%s\">%s</a></td>",
ip, atoi(port) == ? "" : nport, Filename, dirent->d_name); p_time = ctime(&info.st_mtime);//获取文件修改时间
p_passwd = getpwuid(info.st_uid); //获取文件拥有着
p_group = getgrgid(info.st_gid);//获取文件拥有者组 fprintf(client_sock, "<td>%c</td>", file_type(info.st_mode));
fprintf(client_sock, "<td>%s</td>", p_passwd->pw_name);
fprintf(client_sock, "<td>%s</td>", p_group->gr_name);
fprintf(client_sock, "<td>%d</td>", info.st_size);
fprintf(client_sock, "<td>%s</td>", ctime(&info.st_ctime));
}
fprintf(client_sock, "</tr>\n");
free(realFilename);
}
fprintf(client_sock, "</table></center></body></html>");
} else {
//if others,forbid access
fprintf(client_sock,
"HTTP/1.1 200 OK\r\nServer:Test http server\r\nConnection: close\r\n\r\n<html><head><title>permission denied</title></head>"
"<body><font size=+4>Linux HTTP server</font><br><hr width=\"100%%\"><br><center>"
"<table border cols=3 width=\"100%%\">");
fprintf(client_sock,
"</table><font color=\"CC0000\" size=+2> you access resource '%s' forbid to access,communicate with the admintor </font></body></html>",
Path);
}
out:
free(realPath);
free(nport);
} //守护
void init_daemon(const char *pname, int facility)
{
int pid;
int i;
signal(SIGTTOU,SIG_IGN);
signal(SIGTTIN,SIG_IGN);
signal(SIGTSTP,SIG_IGN);
signal(SIGHUP ,SIG_IGN);
if(pid=fork())
exit(EXIT_SUCCESS);
else if(pid< )
{
perror("fork");
exit(EXIT_FAILURE);
}
setsid();
if(pid=fork())
exit(EXIT_SUCCESS);
else if(pid< )
{
perror("fork");
exit(EXIT_FAILURE);
}
for(i=;i< NOFILE;++i)
close(i);
chdir("/tmp");
umask();
signal(SIGCHLD,SIG_IGN);
openlog(pname, LOG_PID, facility);
return;
} //如果配置文件不指定ip 那么默认读取eth0
int get_addr(char *str)
{
int inet_sock;
struct ifreq ifr;
inet_sock = socket(AF_INET, SOCK_DGRAM, );
strcpy(ifr.ifr_name, str);
if (ioctl(inet_sock, SIOCGIFADDR, &ifr) < )
{
wrtinfomsg("bind");
exit(EXIT_FAILURE);
}
sprintf(ip,"%s", inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
}

test_httpd.c

 #include"test_httpd.h"

 int main(int argc, char **argv)
{
struct sockaddr_in addr;
int sock_fd, addrlen; init_daemon(argv[],LOG_INFO);
if(get_arg("home_dir")==)
{
sprintf(home_dir,"%s","/tmp");
}
if(get_arg("ip")==)
{
get_addr("eth0");
}
if(get_arg("port")==)
{
sprintf(port,"%s","");
}
if(get_arg("back")==)
{
sprintf(back,"%s","");
} if ((sock_fd = socket(PF_INET, SOCK_STREAM, )) < )
{
wrtinfomsg("socket()");
exit(EXIT_FAILURE);
}
addrlen = ;
//端口复用 选项SO_REUSEADDR
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen, sizeof(addrlen)); addr.sin_family = AF_INET;
addr.sin_port = htons(atoi(port));
addr.sin_addr.s_addr = inet_addr(ip);
addrlen = sizeof(struct sockaddr_in);
if (bind(sock_fd, (struct sockaddr *) &addr, addrlen) < )
{
wrtinfomsg("bind");
exit(EXIT_FAILURE);
}
if (listen(sock_fd, atoi(back)) < )
{
wrtinfomsg("listen");
exit(EXIT_FAILURE);
}
while ()
{
int len;
int new_fd;
addrlen = sizeof(struct sockaddr_in); new_fd = accept(sock_fd, (struct sockaddr *) &addr, &addrlen);
if (new_fd < )
{
wrtinfomsg("accept");
exit(EXIT_FAILURE);
} bzero(buffer, MAXBUF + );
sprintf(buffer, "connect come from: %s:%d\n",
inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
wrtinfomsg(buffer); //fork a new process to deal with the connect ,the parent continue wait for new connect
pid_t pid;
if((pid=fork())==-)
{
wrtinfomsg("fork");
exit(EXIT_FAILURE);
}
if (pid==)
{
close(sock_fd);
bzero(buffer, MAXBUF + );
if ((len = recv(new_fd, buffer, MAXBUF, )) > )
{
FILE *ClientFP = fdopen(new_fd, "w");
if (ClientFP == NULL)
{
wrtinfomsg("fdopen");
exit(EXIT_FAILURE);
}
else
{
char Req[MAXPATH + ] = "";
sscanf(buffer, "GET %s HTTP", Req);
bzero(buffer, MAXBUF + );
sprintf(buffer, "Reuquest get the file: \"%s\"\n", Req);
wrtinfomsg(buffer);
GiveResponse(ClientFP, Req);
fclose(ClientFP);
}
}
exit(EXIT_SUCCESS);
}
else
{
close(new_fd);
continue;
}
}
close(sock_fd);
return ;
}

makefile

test_httpd: test_httpd.c test_httpd.h
gcc -o test_httpd test_httpd.c test_httpd.h install:
cp test_httpd.conf /etc/test_httpd.conf
cp test_httpd /usr/bin/test_httpd clean:
rm test_httpd uninstall:
rm /usr/bin/test_httpd

test_httpd.conf

 home_dir=/var
port=
back=
ip=写上自己主机上面的IP或者不写

3 运行方法

(1)make

(2)make install 这个时候会把程序添加在PATH路径下

(3)查看端口是否打开

(4)./test_httpd

(5)浏览器访问 htpp://你的ip:port(默认位80,如果指定就写上自己制定的端口)

后面学习线程池的文件服务器

基于http的多进程并发文件服务器的更多相关文章

  1. python多进程并发和多线程并发和协程

    为什么需要并发编程? 如果程序中包含I/O操作,程序会有很高的延迟,CPU会处于等待状态,这样会浪费系统资源,浪费时间 1.Python的并发编程分为多进程并发和多线程并发 多进程并发:运行多个独立的 ...

  2. Appium+python自动化(三十六)- 士兵突击许三多 - 多个appium服务启动,多个设备启动,多进程并发启动设备-并发测试 - 上(超详解)

    简介 前面课程只是启动了单个appium服务,只能控制单台设备.如果需要针对多台设备测试那么该如何处理?而且发现群里的小伙伴们也在时不时地在讨论这个问题,想知道怎么实现的,于是宏哥就决定写一片这样的文 ...

  3. 【redis】基于redis实现分布式并发锁

    基于redis实现分布式并发锁(注解实现) 说明 前提, 应用服务是分布式或多服务, 而这些"多"有共同的"redis"; (2017-12-04) 笑哭, 写 ...

  4. Linux Shell多进程并发以及并发数控制

    1. 基础知识准备 1.1. linux后台进程 Unix是一个多任务系统,允许多用户同时运行多个程序.shell的元字符&提供了在后台运行不需要键盘输入的程序的方法.输入命令后,其后紧跟&a ...

  5. Python多进程并发(multiprocessing)用法实例详解

    http://www.jb51.net/article/67116.htm 本文实例讲述了Python多进程并发(multiprocessing)用法.分享给大家供大家参考.具体分析如下: 由于Pyt ...

  6. 基于RTKLIB构建高并发通信测试工具

    1. RTKLIB基础动态库生成 RTKLIB是全球导航卫星系统GNSS(global navigation satellite system)的标准&精密定位开源程序包,由日本东京海洋大学的 ...

  7. python进阶(一) 多进程并发机制

    python多进程并发机制: 这里使用了multprocessing.Pool进程池,来动态增加进程 #coding=utf-8 from multiprocessing import Pool im ...

  8. python 多进程并发与多线程并发

    本文对python支持的几种并发方式进行简单的总结. Python支持的并发分为多线程并发与多进程并发(异步IO本文不涉及).概念上来说,多进程并发即运行多个独立的程序,优势在于并发处理的任务都由操作 ...

  9. Appium+python自动化(三十七)- 士兵突击许三多 - 多个appium服务启动,多个设备启动,多进程并发启动设备-并发测试 - 下(超详解)

    简介 接着上一篇继续看一下如何并发测试以及并发测试的过程中,可能遇到的问题,在这里宏哥把宏哥遇到的和小伙伴或者童鞋们,一起分享一下. Appium端口检测 问题思考 经过前面学习,我们已经能够使用py ...

随机推荐

  1. [原创]java WEB学习笔记24:MVC案例完整实践(part 5)---删除操作的设计与实现

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  2. 纯CSS3垂直动画菜单

    在线演示 本地下载

  3. web框架详解之tornado 二 cookie

    一.tornado之cookie一 目录: <!DOCTYPE html> <html lang="en"> <head> <meta c ...

  4. Linux Network Namespace

    Linux Network Namespaces Linux kernel在2.6.29中加入了namespaces,用于支持网络的隔离,我们看一下namespace是如何使用的 创建与配置 创建一个 ...

  5. 对unidbgrid的单元格操作

    一.使某行某列单元格disabled: 1. UniStringGrid -> Options -> goEditing = true 2. UniStringGrid -> Ext ...

  6. Alembic Migrations

    Introduction The migrations in the alembic/versions contain the changes needed to migrate from older ...

  7. 文本去重之MinHash算法——就是多个hash函数对items计算特征值,然后取最小的计算相似度

    来源:http://my.oschina.net/pathenon/blog/65210 1.概述     跟SimHash一样,MinHash也是LSH的一种,可以用来快速估算两个集合的相似度.Mi ...

  8. 表达式(exp)

    题目大意 给定一个逻辑表达式,求每一个数满足$\in[1,n]$的使的表达式为真的方案数. 题解 题目限制较奇怪且数据范围较小,所以可以考虑直接暴力. 考虑枚举每一个变量一共出现了$k$种数值,再枚举 ...

  9. P1731 生日蛋糕

    题目背景 7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层 生日蛋糕,每层都是一个圆柱体. 设从下往上数第i(1<=i<=M)层蛋糕是半径为Ri, 高度为Hi的圆柱 ...

  10. 如何利用pyenv 和virtualenv 在单机上搭建多版本python 虚拟开发环境

    pyenv 和virtualenv分别是干什么的? pyenv帮助你在一台机上建立多个版本的python环境, 并提供方便的切换方法. virtualenv则就是将一个目录建立为一个虚拟的python ...