标签:char hid gid 属性 drl hup def 添加 ifreq
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 }
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 { 41 wrtinfomsg("bind"); 42 exit(EXIT_FAILURE); 43 } 44 if (listen(sock_fd, atoi(back)) < 0) 45 { 46 wrtinfomsg("listen"); 47 exit(EXIT_FAILURE); 48 } 49 while (1) 50 { 51 int len; 52 int new_fd; 53 addrlen = sizeof(struct sockaddr_in); 54 55 new_fd = accept(sock_fd, (struct sockaddr *) &addr, &addrlen); 56 if (new_fd < 0) 57 { 58 wrtinfomsg("accept"); 59 exit(EXIT_FAILURE); 60 } 61 62 bzero(buffer, MAXBUF + 1); 63 sprintf(buffer, "connect come from: %s:%d\n", 64 inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 65 wrtinfomsg(buffer); 66 67 //fork a new process to deal with the connect ,the parent continue wait for new connect 68 pid_t pid; 69 if((pid=fork())==-1) 70 { 71 wrtinfomsg("fork"); 72 exit(EXIT_FAILURE); 73 } 74 if (pid==0) 75 { 76 close(sock_fd); 77 bzero(buffer, MAXBUF + 1); 78 if ((len = recv(new_fd, buffer, MAXBUF, 0)) > 0) 79 { 80 FILE *ClientFP = fdopen(new_fd, "w"); 81 if (ClientFP == NULL) 82 { 83 wrtinfomsg("fdopen"); 84 exit(EXIT_FAILURE); 85 } 86 else 87 { 88 char Req[MAXPATH + 1] = ""; 89 sscanf(buffer, "GET %s HTTP", Req); 90 bzero(buffer, MAXBUF + 1); 91 sprintf(buffer, "Reuquest get the file: \"%s\"\n", Req); 92 wrtinfomsg(buffer); 93 GiveResponse(ClientFP, Req); 94 fclose(ClientFP); 95 } 96 } 97 exit(EXIT_SUCCESS); 98 } 99 else 100 { 101 close(new_fd); 102 continue; 103 } 104 } 105 close(sock_fd); 106 return 0; 107 }
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
1 home_dir=/var 2 port=9999 3 back=5 4 ip=写上自己主机上面的IP或者不写
3 运行方法
(1)make
(2)make install 这个时候会把程序添加在PATH路径下
(3)查看端口是否打开
(4)./test_httpd
(5)浏览器访问 htpp://你的ip:port(默认位80,如果指定就写上自己制定的端口)
后面学习线程池的文件服务器
标签:char hid gid 属性 drl hup def 添加 ifreq
原文地址:https://www.cnblogs.com/lanjianhappy/p/10675459.html