linux下的http服务器代码
来源:互联网 发布:codol武器大全数据 编辑:程序博客网 时间:2024/04/28 17:02
/* code c, change the DEFAULTIP to your localhost IP*/ #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> #define DEFAULTIP "127.0.0.1"#define DEFAULTPORT "80"#define DEFAULTBACK "10"#define DEFAULTDIR "/home"#define DEFAULTLOG "/tmp/das-server.log"void prterrmsg(char *msg);#define prterrmsg(msg) { perror(msg); abort(); }void wrterrmsg(char *msg);#define wrterrmsg(msg) { fputs(msg, logfp); fputs(strerror(errno), logfp);fflush(logfp); abort(); }void prtinfomsg(char *msg);#define prtinfomsg(msg) { fputs(msg, stdout); }void wrtinfomsg(char *msg);#define wrtinfomsg(msg) { fputs(msg, logfp); fflush(logfp);}#define MAXBUF 1024 char buffer[MAXBUF + 1];char *host = 0;char *port = 0;char *back = 0;char *dirroot = 0;char *logdir = 0;unsigned char daemon_y_n = 0;FILE *logfp;#define MAXPATH 150/*----------------------------------------*--- dir_up - 查找dirpath所指目录的上一级目录*----------------------------------------*/char *dir_up(char *dirpath){ static char Path[MAXPATH]; int len; strcpy(Path, dirpath); len = strlen(Path); if (len > 1 && Path[len - 1] == '/') len--; while (Path[len - 1] != '/' && len > 1) len--; Path[len] = 0; return Path;} /*------------------------------------------------------ *--- AllocateMemory - 分配空间并把d所指的内容复制 *------------------------------------------------------ */ void AllocateMemory(char **s, int l, char *d) { *s = malloc(l + 1); bzero(*s, l + 1); memcpy(*s, d, l); } /************关于本文档******************************************** *filename: das-server.c *purpose: 这是在Linux下用C语言写的目录访问服务器,支持目录浏览和文件下载 *********************************************************************/ /*------------------------------------------------------ *--- GiveResponse - 把Path所指的内容发送到client_sock去 *-------------------如果Path是一个目录,则列出目录内容 *-------------------如果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; /* 获得实际工作目录或文件 */ len = strlen(dirroot) + strlen(Path) + 1; realPath = malloc(len + 1); bzero(realPath, len + 1); sprintf(realPath, "%s/%s", dirroot, Path); /* 获得实际工作端口 */ len = strlen(port) + 1; nport = malloc(len + 1); bzero(nport, len + 1); sprintf(nport, ":%s", port); /* 获得实际工作目录或文件的信息以判断是文件还是目录 */ if (stat(realPath, &info)) { fprintf(client_sock, "HTTP/1.1 200 OK\r\nServer:SONG\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n\r\n<html><head><title>%d - %s</title></head>" "<body><font size=+4>Linux 下目录访问服务器</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>请向管理员咨询为何出现如下错误提示:\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, 0, SEEK_END); p = (char *) malloc(len + 1); bzero(p, len + 1); lseek(fd, 0, SEEK_SET); ret = read(fd, p, len); close(fd); fprintf(client_sock, "HTTP/1.1 200 OK\r\nServer:SONG\r\nConnection: keep-alive\r\nContent-type: application/*\r\nContent-Length:%d\r\n\r\n", len); fwrite(p, len, 1, client_sock); free(p); } else if (S_ISDIR(info.st_mode)) { /* 处理浏览目录请求 */ dir = opendir(realPath); fprintf(client_sock, "HTTP/1.1 200 OK\r\nServer:SONG\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n\r\n<html><head><title>%s</title></head>" "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>" "<table border cols=3 width=\"100%%\">", Path); fprintf(client_sock, "<caption><font size=+3>目录 %s</font></caption>\n", Path); fprintf(client_sock, "<tr><td>名称</td><td>大小</td><td>修改时间</td></tr>\n"); if (dir == 0) { fprintf(client_sock, "</table><font color=\"CC0000\" size=+2>%s</font></body></html>", strerror(errno)); return; } /* 读取目录里的所有内容 */ while ((dirent = readdir(dir)) != 0) { if (strcmp(Path, "/") == 0) sprintf(Filename, "/%s", dirent->d_name); else sprintf(Filename, "%s/%s", Path, dirent->d_name); fprintf(client_sock, "<tr>"); len = strlen(dirroot) + strlen(Filename) + 1; realFilename = malloc(len + 1); bzero(realFilename, len + 1); sprintf(realFilename, "%s/%s", dirroot, Filename); if (stat(realFilename, &info) == 0) { if (strcmp(dirent->d_name, "..") == 0) fprintf(client_sock, "<td><a href=\"http://%s%s%s\">(parent)</a></td>", host, atoi(port) == 80 ? "" : nport, dir_up(Path)); else fprintf(client_sock, "<td><a href=\"http://%s%s%s\">%s</a></td>", host, atoi(port) == 80 ? "" : nport, Filename, dirent->d_name); if (S_ISDIR(info.st_mode)) fprintf(client_sock, "<td>目录</td>"); else if (S_ISREG(info.st_mode)) fprintf(client_sock, "<td>%d</td>", info.st_size); else if (S_ISLNK(info.st_mode)) fprintf(client_sock, "<td>链接</td>"); else if (S_ISCHR(info.st_mode)) fprintf(client_sock, "<td>字符设备</td>"); else if (S_ISBLK(info.st_mode)) fprintf(client_sock, "<td>块设备</td>"); else if (S_ISFIFO(info.st_mode)) fprintf(client_sock, "<td>FIFO</td>"); else if (S_ISSOCK(info.st_mode)) fprintf(client_sock, "<td>Socket</td>"); else fprintf(client_sock, "<td>(未知)</td>"); 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 { /* 既非常规文件又非目录,禁止访问 */ fprintf(client_sock, "HTTP/1.1 200 OK\r\nServer:SONG\r\nConnection: close\r\nContent-Type:text/html; charset=UTF-8\r\n<html><head><title>permission denied</title></head>" "<body><font size=+4>Linux 下目录访问服务器</font><br><hr width=\"100%%\"><br><center>" "<table border cols=3 width=\"100%%\">"); fprintf(client_sock, "</table><font color=\"CC0000\" size=+2>你访问的资源'%s'被禁止访问,请联系管理员解决!</font></body></html& gt;", Path); } out: free(realPath); free(nport); } /*------------------------------------------------------*--- getoption - 分析取出程序的参数 *------------------------------------------------------*/void getoption(int argc, char **argv){ int c, len; char *p = 0; opterr = 0; while (1) { int option_index = 0; static struct option long_options[] = { {"host", 1, 0, 0}, {"port", 1, 0, 0}, {"back", 1, 0, 0}, {"dir", 1, 0, 0}, {"log", 1, 0, 0}, {"daemon", 0, 0, 0}, {0, 0, 0, 0} }; /* 本程序支持如一些参数: * --host IP地址 或者 -H IP地址 * --port 端口 或者 -P 端口 * --back 监听数量 或者 -B 监听数量 * --dir 网站根目录 或者 -D 网站根目录 * --log 日志存放路径 或者 -L 日志存放路径 * --daemon 使程序进入后台运行模式 */ c = getopt_long(argc, argv, "H:P:B:D:L", long_options, &option_index); if (c == -1 || c == '?') break; if(optarg) len = strlen(optarg); else len = 0; if ((!c && !(strcasecmp(long_options[option_index].name, "host"))) || c == 'H') p = host = malloc(len + 1); else if ((!c && !(strcasecmp(long_options[option_index].name, "port"))) || c == 'P') p = port = malloc(len + 1); else if ((!c && !(strcasecmp(long_options[option_index].name, "back"))) || c == 'B') p = back = malloc(len + 1); else if ((!c && !(strcasecmp(long_options[option_index].name, "dir"))) || c == 'D') p = dirroot = malloc(len + 1); else if ((!c && !(strcasecmp(long_options[option_index].name, "log"))) || c == 'L') p = logdir = malloc(len + 1); else if ((!c && !(strcasecmp (long_options[option_index].name, "daemon")))) { daemon_y_n = 1; continue; } else break; bzero(p, len + 1); memcpy(p, optarg, len); } } int main(int argc, char **argv) { struct sockaddr_in addr; struct sockaddr_in my_addr; my_addr.sin_addr.s_addr=htonl(INADDR_ANY); int sock_fd, addrlen; /* 获得程序工作的参数,如 IP 、端口、监听数、网页根目录、目录存放位置等 */ getoption(argc, argv); if (!host) { addrlen = strlen(DEFAULTIP); AllocateMemory(&host, addrlen,DEFAULTIP); } if (!port) { addrlen = strlen(DEFAULTPORT); AllocateMemory(&port, addrlen, DEFAULTPORT); } if (!back) { addrlen = strlen(DEFAULTBACK); AllocateMemory(&back, addrlen, DEFAULTBACK); } if (!dirroot) { addrlen = strlen(DEFAULTDIR); AllocateMemory(&dirroot, addrlen, DEFAULTDIR); } if (!logdir) { addrlen = strlen(DEFAULTLOG); AllocateMemory(&logdir, addrlen, DEFAULTLOG); } printf ("host=%s port=%s back=%s dirroot=%s logdir=%s %s是后台工作模式(进程ID:%d)\n", host, port, back, dirroot, logdir, daemon_y_n?"":"不", getpid()); /* fork() 两次处于后台工作模式下 */ if (daemon_y_n) { if (fork()) exit(0); if (fork()) exit(0); close(0), close(1), close(2); logfp = fopen(logdir, "a+"); if (!logfp) exit(0); } /* 处理子进程退出以免产生僵尸进程 */ signal(SIGCHLD, SIG_IGN); /* 创建 socket */ if ((sock_fd = socket(PF_INET, SOCK_STREAM, 0)) < 0) { if (!daemon_y_n) { prterrmsg("socket()"); } else { wrterrmsg("socket()"); } } /* 设置端口快速重用 */ addrlen = 1; 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(host); addrlen = sizeof(struct sockaddr_in); /* 绑定地址、端口等信息 */ if (bind(sock_fd, (struct sockaddr *) &addr, addrlen) < 0) { if (!daemon_y_n) { prterrmsg("bind()"); } else { wrterrmsg("bind()"); } } /* 开启临听 */ if (listen(sock_fd, atoi(back)) < 0) { if (!daemon_y_n) { prterrmsg("listen()"); } else { wrterrmsg("listen()"); } } while (1) { int len; int new_fd; addrlen = sizeof(struct sockaddr_in); /* 接受新连接请求 */ new_fd = accept(sock_fd, (struct sockaddr *) &addr, &addrlen); if (new_fd < 0) { if (!daemon_y_n) { prterrmsg("accept()"); } else { wrterrmsg("accept()"); } break; } bzero(buffer, MAXBUF + 1); sprintf(buffer, "连接来自于: %s:%d\n",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); if (!daemon_y_n) { prtinfomsg(buffer); } else { wrtinfomsg(buffer); } /* 产生一个子进程去处理请求,当前进程继续等待新的连接到来 */ if (!fork()) { bzero(buffer, MAXBUF + 1); if ((len = recv(new_fd, buffer, MAXBUF, 0)) > 0) { FILE *ClientFP = fdopen(new_fd, "w"); if (ClientFP == NULL) { if (!daemon_y_n) { prterrmsg("fdopen()"); } else { prterrmsg("fdopen()"); } } else { char Req[MAXPATH + 1] = ""; sscanf(buffer, "GET %s HTTP", Req); bzero(buffer, MAXBUF + 1); sprintf(buffer, "请求取文件: \"%s\"\n", Req); if (!daemon_y_n) { prtinfomsg(buffer); } else { wrtinfomsg(buffer); } /* 处理用户请求 */ GiveResponse(ClientFP, Req); fclose(ClientFP); } } exit(0); } close(new_fd); } close(sock_fd); return 0; }
Linux下HTTP Server
想在Linux下实现一个简单的web Server并不难。一个最简单的HTTP Server不过是一个高级的文件服务器,不断地接收客户端(浏览器)发送的HTTP请求,解析请求,处理请求,然后像客户端回送数据。在大多是情况下,(GET、POST命令),服务求回传给客户端的都是文件(HTML 文档, 图片,javascript脚本等等)。
下面是一个极简单的HTTP Server的demo,虽然只处理GET请求并发送单一文件,但基本展示了web server的框架。我的例子试图将功能和结构做到最精简,这样,一个http server的基本结构,便一目了然。
#include<sys/socket.h>#include<errno.h>#include<netinet/in.h>#include<string.h>#include<stdio.h>#define BUF_LEN 1028#define SERVER_PORT 8080//定义好的html页面,实际情况下web server基本是从本地文件系统读取html文件 const static char http_error_hdr[] = "HTTP/1.1 404 Not Found\r\nContent-type: text/html\r\n\r\n";const static char http_html_hdr[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n";const static char http_index_html[] = "<html><head><title>Congrats!</title></head>""<body><h1>Welcome to our HTTP server demo!</h1>""<p>This is a just small test page.</body></html>";//解析到HTTP请求的文件后,发送本地文件系统中的文件//这里,我们处理对index文件的请求,发送我们预定好的html文件//呵呵,一切从简! int http_send_file(char *filename, int sockfd){ if(!strcmp(filename, "/")){ //通过write函数发送http响应报文;报文包括HTTP响应头和响应内容--HTML文件 write(sockfd, http_html_hdr, strlen(http_html_hdr)); write(sockfd, http_index_html, strlen(http_index_html)); } else{ // 文件未找到情况下发送404error响应 printf("%s:file not find!\n",filename); write(sockfd, http_error_hdr, strlen(http_error_hdr)); } return 0;}//HTTP请求解析 void serve(int sockfd){char buf[BUF_LEN];read(sockfd, buf, BUF_LEN);if(!strncmp(buf, "GET", 3)){char *file = buf + 4; char *space = strchr(file, ' '); *space = '\0'; http_send_file(file, sockfd);}else{ //其他HTTP请求处理,如POST,HEAD等 。这里我们只处理GET printf("unsupported request!\n");return;}}void main(){int sockfd,err,newfd;struct sockaddr_in addr;//建立TCP套接字 sockfd = socket(AF_INET, SOCK_STREAM, 0);if(sockfd < 0){perror("socket creation failed!\n");return;}memset(&addr, 0, sizeof(addr));addr.sin_family = AF_INET;//这里要注意,端口号一定要使用htons先转化为网络字节序,否则绑定的实际端口//可能和你需要的不同 addr.sin_port = htons(SERVER_PORT);addr.sin_addr.s_addr = INADDR_ANY;if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))){perror("socket binding failed!\n");return;}listen(sockfd, 128);for(;;){ //不间断接收HTTP请求并处理,这里使用单线程,在实际情况下考虑到效率一般多线程 newfd = accept(sockfd, NULL, NULL);serve(newfd);close(newfd);}}
0 0
- linux下的http服务器代码
- (转)linux下的http服务器代码
- linux下的http服务器
- linux下的http服务器
- linux下的http服务器
- Linux下HTTP服务器的搭建
- linux下构建http服务器
- Linux下的http服务器 v0.0.0.0.0.0.1
- linux下查询http连接的服务器信息
- Linux下基于http的小型web服务器编写
- 【Linux技术】linux下http服务器开发
- Linux下Apache http 服务器安装配置
- 服务器 Linux下http.conf详解
- Linux 下 ngnix 搭建 http 服务器
- HTTP服务器返回的代码详解
- linux 下非阻塞客户端,服务器代码
- linux下epoll服务器代码实现
- Linux服务器教程之路4--Linux下Apache HTTP服务器与代理服务器的搭建
- extern “C”作用详解
- C++中四种类型转换方式
- 编译器技术简析(一)- Lexical Analysis之NFA-DFA
- Arrays_Strings 把字符串中所有的空格替换为%20 @CareerCup
- 游戏中常用的设计模式
- linux下的http服务器代码
- Construct Binary Tree from Preorder and Inorder Traversal
- const与#define优缺点
- if判断和比较
- 杨幂与刘恺威首度合体古装戏 曝因怀孕辞演秋香
- HDU 4722 Good Numbers
- NYOJ NO.5 Binary String Matching
- NYOJ NO.86 找球号(一)
- Construct Binary Tree from Inorder and Postorder Traversal