基于http的多进程并发文件服务器

Posted L的存在

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于http的多进程并发文件服务器相关的知识,希望对你有一定的参考价值。

1 可以掌握的知识点

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

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

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

(4) 多进程知识

2 代码注释如下

test_httpd.h

  1 #include <pwd.h>
  2 #include <grp.h>
  3 #include <net/if.h>
  4 #include <sys/ioctl.h>
  5 #include <sys/syslog.h>
  6 #include <stdarg.h>
  7 #include <errno.h>
  8 #include <stdio.h>
  9 #include <fcntl.h>
 10 #include <unistd.h>
 11 #include <string.h>
 12 #include <time.h>
 13 #include <sys/types.h>
 14 #include <sys/stat.h>
 15 #include <dirent.h>
 16 #include <errno.h>
 17 #include <netinet/in.h>
 18 #include <sys/socket.h>
 19 #include <resolv.h>
 20 #include <arpa/inet.h>
 21 #include <stdlib.h>
 22 #include <signal.h>
 23 #include <getopt.h>
 24 #include <net/if.h>
 25 #include <sys/ioctl.h>
 26 
 27 #define MAXBUF        1024
 28 #define MAXPATH        128
 29 
 30 char buffer[MAXBUF + 1];
 31 char ip[128];//存储字符串形式的Ip地址
 32 char port[128];//存储字符串形式的端口
 33 char back[128];//listen队列大小
 34 char home_dir[128];//浏览主目录
 35 
 36 
 37 void wrtinfomsg(char *msg)        
 38 {  
 39     syslog(LOG_INFO,"%s",msg);
 40 }
 41 
 42 
 43 //读取配置文件
 44 int get_arg (char *cmd)
 45 {
 46 
 47         FILE* fp;
 48         char buffer[1024];
 49         size_t bytes_read;
 50         char* match;
 51         fp = fopen ("/etc/test_httpd.conf", "r");
 52         bytes_read = fread (buffer, 1, sizeof (buffer), fp);
 53         fclose (fp);
 54 
 55         if (bytes_read == 0 || bytes_read == sizeof (buffer))
 56                 return 0;
 57         buffer[bytes_read] = \'\\0\';
 58         
 59         //根据配置文件key得到value
 60         if(!strncmp(cmd,"home_dir",8))
 61         {
 62                 match = strstr (buffer, "home_dir=");
 63                 if (match == NULL)
 64                         return 0;
 65                 bytes_read=sscanf(match,"home_dir=%s",home_dir);
 66                 return bytes_read;
 67         }
 68 
 69         else if(!strncmp(cmd,"port",4))
 70         {
 71                 match = strstr (buffer, "port=");
 72                 if (match == NULL)
 73                         return 0;
 74                 bytes_read=sscanf(match,"port=%s",port);
 75                 return bytes_read;
 76         }
 77 
 78         else if(!strncmp(cmd,"ip",2))
 79         {
 80                 match = strstr (buffer, "ip=");
 81                 if (match == NULL)
 82                         return 0;
 83                 bytes_read=sscanf(match,"ip=%s",ip);
 84                 return bytes_read;
 85         }
 86         else if(!strncmp(cmd,"back",4))
 87         {
 88                 match = strstr (buffer, "back=");
 89                 if (match == NULL)
 90                         return 0;
 91                 bytes_read=sscanf(match,"back=%s",back);
 92                 return bytes_read;
 93         }
 94      else
 95             return 0;
 96 }
 97 
 98 //文件类型的判断
 99 char file_type(mode_t st_mode)
100 {
101     if ((st_mode & S_IFMT) == S_IFSOCK)
102         return \'s\';
103     else if ((st_mode & S_IFMT) == S_IFLNK)
104         return \'l\';
105     else if ((st_mode & S_IFMT) == S_IFREG)
106         return \'-\';
107     else if ((st_mode & S_IFMT) == S_IFBLK)
108         return \'b\';
109     else if ((st_mode & S_IFMT) == S_IFCHR)
110         return \'c\';
111     else if ((st_mode & S_IFMT) == S_IFIFO)
112         return \'p\';
113     else
114         return \'d\';
115 }
116 
117 //search the up-path of dirpath
118 char *dir_up(char *dirpath)
119 {
120     static char Path[MAXPATH];
121     int len;
122 
123     strcpy(Path, dirpath);
124     len = strlen(Path);
125     if (len > 1 && Path[len - 1] == \'/\')
126         len--;
127     while (Path[len - 1] != \'/\' && len > 1)
128         len--;
129     Path[len] = 0;
130     return Path;
131 }
132 
133 //如果路径是文件 就将文件的内容发送过去 如果是目录则列出目录文件
134 void GiveResponse(FILE * client_sock, char *Path)
135 {
136     struct dirent *dirent;
137     struct stat info;
138     char Filename[MAXPATH];
139     DIR *dir;
140     int fd, len, ret;
141     char *p, *realPath, *realFilename, *nport;
142 
143     struct passwd *p_passwd;
144     struct group *p_group;
145     char *p_time;    
146 
147     //get th dir or file
148     len = strlen(home_dir) + strlen(Path) + 1;
149     realPath = malloc(len + 1);
150     bzero(realPath, len + 1);
151     sprintf(realPath, "%s/%s", home_dir, Path);//获取文件的绝对路径
152 
153     //get port
154     len = strlen(port) + 1;
155     nport = malloc(len + 1);
156     bzero(nport, len + 1);
157     sprintf(nport, ":%s", port);//存储端口信息
158 
159 
160     
161     //获取文件属性
162     if (stat(realPath, &info)) {
163         //获取失败   输出这样信息 这信息格式满足http协议
164         fprintf(client_sock,
165                 "HTTP/1.1 200 OK\\r\\nServer:Test http server\\r\\nConnection: close\\r\\n\\r\\n<html><head><title>%d - %s</title></head>"
166                 "<body><font size=+4>Linux HTTP server</font><br><hr width=\\"100%%\\"><br><center>"
167                 "<table border cols=3 width=\\"100%%\\">", errno,
168                 strerror(errno));
169         fprintf(client_sock,
170                 "</table><font color=\\"CC0000\\" size=+2> connect to administrator, error code is: \\n%s %s</font></body></html>",
171                 Path, strerror(errno));
172         goto out;
173     }
174 
175     //如果是文件则下载
176     if (S_ISREG(info.st_mode)) 
177     {
178         fd = open(realPath, O_RDONLY);
179         len = lseek(fd, 0, SEEK_END);
180         p = (char *) malloc(len + 1);
181         bzero(p, len + 1);
182         lseek(fd, 0, SEEK_SET);
183         //这里是一次性读取 小文件
184         ret = read(fd, p, len);
185         close(fd);
186         fprintf(client_sock,
187                 "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);
188        
189         fwrite(p, len, 1, client_sock);
190         free(p);
191     } 
192     else if (S_ISDIR(info.st_mode)) 
193     {
194 
195     //列出目录
196         dir = opendir(realPath);
197         fprintf(client_sock,
198                 "HTTP/1.1 200 OK\\r\\nServer:Test http server\\r\\nConnection:close\\r\\n\\r\\n<html><head><title>%s</title></head>"
199                 "<body><font size=+4>Linux HTTP server file</font><br><hr width=\\"100%%\\"><br><center>"
200                 "<table border cols=3 width=\\"100%%\\">", Path);
201         fprintf(client_sock,
202                 "<caption><font size=+3> Directory %s</font></caption>\\n",
203                 Path);
204         fprintf(client_sock,
205                 "<tr><td>name</td><td>type</td><td>owner</td><td>group</td><td>size</td><td>modify time</td></tr>\\n");
206         if (dir == NULL) {
207             fprintf(client_sock, "</table><font color=\\"CC0000\\" size=+2>%s</font></body></html>",
208                     strerror(errno));
209             return;
210         }
211         while ((dirent = readdir(dir)) != NULL) 
212         {
213             if (strcmp(Path, "/") == 0)
214                 sprintf(Filename, "/%s", dirent->d_name);
215             else
216                 sprintf(Filename, "%s/%s", Path, dirent->d_name);
217             if(dirent->d_name[0]==\'.\')
218                 continue;
219             fprintf(client_sock, "<tr>");
220             len = strlen(home_dir) + strlen(Filename) + 1;
221             realFilename = malloc(len + 1);
222             bzero(realFilename, len + 1);
223             sprintf(realFilename, "%s/%s", home_dir, Filename);
224             if (stat(realFilename, &info) == 0) 
225             {
226                 if (strcmp(dirent->d_name, "..") == 0)
227                     fprintf(client_sock, "<td><a href=\\"http://%s%s%s\\">(parent)</a></td>",
228                             ip, atoi(port) == 80 ? "" : nport,dir_up(Path));
229                 else
230                     fprintf(client_sock, "<td><a href=\\"http://%s%s%s\\">%s</a></td>",
231                             ip, atoi(port) == 80 ? "" : nport, Filename, dirent->d_name);
232                
233 
234 
235                   p_time = ctime(&info.st_mtime);//获取文件修改时间
236                    p_passwd = getpwuid(info.st_uid);    //获取文件拥有着
237                    p_group = getgrgid(info.st_gid);//获取文件拥有者组
238 
239                   fprintf(client_sock, "<td>%c</td>", file_type(info.st_mode));
240                    fprintf(client_sock, "<td>%s</td>", p_passwd->pw_name);
241                   fprintf(client_sock, "<td>%s</td>", p_group->gr_name);
242                   fprintf(client_sock, "<td>%d</td>", info.st_size);
243                 fprintf(client_sock, "<td>%s</td>", ctime(&info.st_ctime));
244             }
245             fprintf(client_sock, "</tr>\\n");
246             free(realFilename);
247         }
248         fprintf(client_sock, "</table></center></body></html>");
249     } else {
250       //if others,forbid access
251         fprintf(client_sock,
252                 "HTTP/1.1 200 OK\\r\\nServer:Test http server\\r\\nConnection: close\\r\\n\\r\\n<html><head><title>permission denied</title></head>"
253                 "<body><font size=+4>Linux HTTP server</font><br><hr width=\\"100%%\\"><br><center>"
254                 "<table border cols=3 width=\\"100%%\\">");
255         fprintf(client_sock,
256                 "</table><font color=\\"CC0000\\" size=+2> you access resource \'%s\' forbid to access,communicate with the admintor </font></body></html>",
257                 Path);
258     }
259   out:
260     free(realPath);
261     free(nport);
262 }
263 
264 //守护
265 void init_daemon(const char *pname, int facility)
266 {
267     int pid; 
268     int i;
269     signal(SIGTTOU,SIG_IGN); 
270     signal(SIGTTIN,SIG_IGN); 
271     signal(SIGTSTP,SIG_IGN); 
272     signal(SIGHUP ,SIG_IGN);
273     if(pid=fork()) 
274         exit(EXIT_SUCCESS); 
275     else if(pid< 0) 
276     {
277         perror("fork");
278         exit(EXIT_FAILURE);
279     }
280     setsid(); 
281     if(pid=fork()) 
282         exit(EXIT_SUCCESS); 
283     else if(pid< 0) 
284     {
285         perror("fork");
286         exit(EXIT_FAILURE);
287     }  
288     for(i=0;i< NOFILE;++i)
289         close(i);
290     chdir("/tmp"); 
291     umask(0);  
292     signal(SIGCHLD,SIG_IGN);
293     openlog(pname, LOG_PID, facility);
294     return; 
295 } 
296 
297 //如果配置文件不指定ip  那么默认读取eth0
298 int get_addr(char *str)
299 {
300         int inet_sock;
301         struct ifreq ifr;
302         inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
303         strcpy(ifr.ifr_name, str);
304         if (ioctl(inet_sock, SIOCGIFADDR, &ifr) < 0)
305         {
306             wrtinfomsg("bind");
307             exit(EXIT_FAILURE);
308         }
309         sprintf(ip,"%s", inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
310 }
View Code

test_httpd.c

  1 #include"test_httpd.h"
  2 
  3 int main(int argc, char **argv)
  4 {
  5     struct sockaddr_in addr;
  6     int sock_fd, addrlen;
  7     
  8     init_daemon(argv[0],LOG_INFO);
  9     if(get_arg("home_dir")==0)
 10     {
 11         sprintf(home_dir,"%s","/tmp");
 12     }
 13     if(get_arg("ip")==0)
 14     {
 15         get_addr("eth0");
 16     }
 17     if(get_arg("port")==0)
 18     {
 19         sprintf(port,"%s","80");
 20     }
 21     if(get_arg("back")==0)
 22     {
 23         sprintf(back,"%s","5");
 24     }
 25 
 26     if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) 
 27     {
 28         wrtinfomsg("socket()");
 29         exit(EXIT_FAILURE);
 30     }
 31     addrlen = 1;
 32     //端口复用 选项SO_REUSEADDR
 33     setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &addrlen, sizeof(addrlen));
 34 
 35     addr.sin_family = AF_INET;
 36     addr.sin_port = htons(atoi(port));
 37     addr.sin_addr.s_addr = inet_addr(ip);
 38     addrlen = sizeof(struct sockaddr_in);
 39     if (bind(sock_fd, (struct sockaddr *) &addr, addrlen) < 0)
 40 cpp►多线程

python中的多线程和多进程编程

基于LINUX下的多线程

python并发编程中的多进程(代码实现)

Java多线程总结

python3全栈开发-并发编程的多进程理论