【OpenSource】--TinyHttpD
2016-01-22 16:36
337 查看
【源码下载】http://sourceforge.net/projects/tinyhttpd/files/tinyhttpd%20source/tinyhttpd%200.1.0/tinyhttpd-0.1.0.tar.gz/download
【编译环境】ubuntu14.04+gcc
【运 行】工程利用了多线程,需要链接多线程的库libpthread.so;直接编译httpd.c源文件 $ gcc -o 程序名 源文件.c -lpthread 然后在浏览器输入: localhost:程序动态分配的端口号/index.html就可运行了。
请求头:
响应头:
【注 意】源代码中提示将多线程注释掉,注释掉后直接编译不能运行。不注释直接编译虽然会又warnning但可运行。
服务器端原理:
服务器端调用socket()建立socket套接字,调用bind()函数绑定IP和端口,调用listen()函数监听端口,等待浏览器发送URL,调用accept()函数接受数据,关闭套接字。
accept()函数中创建多线程,主线程继续等待,子线程处理http请求,解析浏览器发送的URL字符串,结束后新线程退出。
main():
主函数调用startup()函数创建套接字。其中有一点是sockaddr和sockaddr_in的不同,总结是先创建sockaddr_in结构体,将该结构体中的各个变量赋值完后,在bind()或者accept()函数中将其转化为sockaddr结构体,因为两者所占内存空间一样可相互转化,另外两者所在头文件不一样,sockaddr在socket.h中,sockaddr_in在in.h中。
startup():
startup()函数返回套接字后创建多线程,多线程函数起始为accept_request()函数。
accept_request():
处理静态文件函数serv_file():
发送一个文件到客户端,调用headers()发送响应头。调用cat()函数将一个文件的内容输出到socket。
【编译环境】ubuntu14.04+gcc
【运 行】工程利用了多线程,需要链接多线程的库libpthread.so;直接编译httpd.c源文件 $ gcc -o 程序名 源文件.c -lpthread 然后在浏览器输入: localhost:程序动态分配的端口号/index.html就可运行了。
请求头:
【GET】【http://localhost:59776/index.html】 Host: localhost:59776 User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:39.0) Gecko/20100101 Firefox/39.0 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3 Accept-Encoding: gzip, deflate Connection: keep-alive
响应头:
Content-Type: text/html Server: jdbhttpd/0.1.0
【注 意】源代码中提示将多线程注释掉,注释掉后直接编译不能运行。不注释直接编译虽然会又warnning但可运行。
服务器端原理:
服务器端调用socket()建立socket套接字,调用bind()函数绑定IP和端口,调用listen()函数监听端口,等待浏览器发送URL,调用accept()函数接受数据,关闭套接字。
accept()函数中创建多线程,主线程继续等待,子线程处理http请求,解析浏览器发送的URL字符串,结束后新线程退出。
main():
int main(void) { int server_sock = -1; u_short port = 0; int client_sock = -1; struct sockaddr_in client_name; int client_name_len = sizeof(client_name); pthread_t newthread; server_sock = startup(&port); //传递port的地址到startup()函数 printf("httpd running on port %d\n", port); while (1) { client_sock = accept(server_sock, (struct sockaddr *)&client_name, &client_name_len); if (client_sock == -1) error_die("accept"); /* accept_request(client_sock); */ if (pthread_create(&newthread , NULL, accept_request, client_sock) != 0) perror("pthread_create"); } close(server_sock); return(0); }
主函数调用startup()函数创建套接字。其中有一点是sockaddr和sockaddr_in的不同,总结是先创建sockaddr_in结构体,将该结构体中的各个变量赋值完后,在bind()或者accept()函数中将其转化为sockaddr结构体,因为两者所占内存空间一样可相互转化,另外两者所在头文件不一样,sockaddr在socket.h中,sockaddr_in在in.h中。
startup():
int startup(u_short *port) { int httpd = 0; struct sockaddr_in name; //声明结构体 httpd = socket(PF_INET, SOCK_STREAM, 0); //创建套接字 if (httpd == -1) error_die("socket"); memset(&name, 0, sizeof(name)); //初始化 name.sin_family = AF_INET; //协议簇赋值 name.sin_port = htons(*port); name.sin_addr.s_addr = htonl(INADDR_ANY); if (bind(httpd, (struct sockaddr *)&name, sizeof(name)) < 0) //绑定IP和端口 error_die("bind"); if (*port == 0) /* if dynamically allocating a port */ { int namelen = sizeof(name); if (getsockname(httpd, (struct sockaddr *)&name, &namelen) == -1) error_die("getsockname"); *port = ntohs(name.sin_port);//动态分配端口 } if (listen(httpd, 5) < 0) //监听套接字 error_die("listen"); return(httpd); //返回套接字 }
startup()函数返回套接字后创建多线程,多线程函数起始为accept_request()函数。
accept_request():
void accept_request(int client) { char buf[1024]; int numchars; char method[255]; char url[255]; char path[512]; size_t i, j; struct stat st; int cgi = 0; /* becomes true if server decides this is a CGI * program */ char *query_string = NULL; numchars = get_line(client, buf, sizeof(buf)); i = 0; j = 0; while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) { method[i] = buf[j]; i++; j++; } method[i] = '\0'; //判断请求方式 if (strcasecmp(method, "GET") && strcasecmp(method, "POST")) { unimplemented(client); return; } if (strcasecmp(method, "POST") == 0) cgi = 1; i = 0; while (ISspace(buf[j]) && (j < sizeof(buf))) j++; while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) { url[i] = buf[j]; i++; j++; } url[i] = '\0'; //GET方式 if (strcasecmp(method, "GET") == 0) { query_string = url; while ((*query_string != '?') && (*query_string != '\0')) query_string++; if (*query_string == '?') { cgi = 1; *query_string = '\0'; query_string++; } } sprintf(path, "htdocs%s", url);//默认路径为工程下的htddocs文件夹下index.html if (path[strlen(path) - 1] == '/') strcat(path, "index.html"); if (stat(path, &st) == -1) { while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ numchars = get_line(client, buf, sizeof(buf)); not_found(client); } else { if ((st.st_mode & S_IFMT) == S_IFDIR) strcat(path, "/index.html"); if ((st.st_mode & S_IXUSR) || (st.st_mode & S_IXGRP) || (st.st_mode & S_IXOTH) ) cgi = 1; if (!cgi) serve_file(client, path); //处理静态页面 else execute_cgi(client, path, method, query_string); } close(client); }
处理静态文件函数serv_file():
发送一个文件到客户端,调用headers()发送响应头。调用cat()函数将一个文件的内容输出到socket。
void serve_file(int client, const char *filename) { FILE *resource = NULL; int numchars = 1; char buf[1024]; buf[0] = 'A'; buf[1] = '\0'; while ((numchars > 0) && strcmp("\n", buf)) /* read & discard headers */ //读取一行,将以\n或\r\n结束的字符串,转化为以\n\0字符结束 numchars = get_line(client, buf, sizeof(buf)); resource = fopen(filename, "r"); if (resource == NULL) not_found(client); else { //响应头 headers(client, filename); cat(client, resource); } fclose(resource); } void headers(int client, const char *filename) { char buf[1024]; (void)filename; /* could use filename to determine file type */ strcpy(buf, "HTTP/1.0 200 OK\r\n"); send(client, buf, strlen(buf), 0); strcpy(buf, SERVER_STRING); send(client, buf, strlen(buf), 0); sprintf(buf, "Content-Type: text/html\r\n"); send(client, buf, strlen(buf), 0); strcpy(buf, "\r\n"); send(client, buf, strlen(buf), 0); } void cat(int client, FILE *resource) { char buf[1024]; fgets(buf, sizeof(buf), resource); while (!feof(resource)) { send(client, buf, strlen(buf), 0); fgets(buf, sizeof(buf), resource); } }
相关文章推荐
- Android5.0以下WebView实现访问Https双向认证网页
- Http通信过程(7步)
- ajax--怎么用ajax做到无刷新
- SGU 326 Perspective (网络流)
- linux常用命令—— 网络通信(十)
- 【图解HTTP】第二章 简单的http协议
- linux常用命令—— 网络通信(九)
- 利用XMLHttpRequest level 2 实现文件异步上传
- ajax--无ajax做到无刷新
- .NET/MVC-发布到IIS6.1提示未能加载程序集System.Web.Http.WebHost
- 深度卷积网络-LeNet-5深度解析
- 关于ip_conntrack跟踪连接满导致网络丢包问题的分析
- 高级编程之网络编程(四)
- 高级编程之网络编程(三)
- 高级编程之网络编程(二)
- Project Euler 107:Minimal network 最小网络
- 高级编程之网络编程(一)
- discuz登录出现HTTP Error 404. The requested resource is not found.
- POJ 3281 Dining (网络流)
- SpringMVC之表单提交===③===多文件上传表单 http://h-king.iteye.com/blog/2269217