为何须要支持虚拟端口? html
若是不支持虚拟端口,每个ip只能对应一个网站。再对应别的域名就须要加端口了。 web
支持虚拟端口的原理?? ubuntu
首先,咱们知道,当多个域名与一个ip相对。DNS只能提供ip地址,没法提供端口号。因此web browser没法知道多个域名与一个ip对应的时候那个域名应该使用哪一个端口。当用户不能提供端口web browser只能使用80默认端口了。咱们在DNS无法作人和做用。只能在web browser和web服务器上作手脚。web browser在发送request请求的时候,添加一个HOST项,web 服务器检查就能够了。 服务器
我就以将localhost和127.0.0.1对应不一样的网站为例吧,可能不是很恰当,可是能够用来讲明问题。若是向给好的话,能够经过修改host,将不一样的域名对应到本地就好了。 socket
下面主要代码:(本程序只是一个例子,只是用来讲明原理,其中可有与实际开发中不容许的操做,也能会出现错误的,请你们谅解。本程序本人只在ubuntu12.04中使用系统默认的gcc编译成功,运行成功。在其余系统中为进行实验,请谅解。)完整代码在最下面 完整代码下载 函数
//虚拟端口处理操做。 void virtual_port_handler(char *buf, int connf) { char virtal_uri[] = "127.0.0.1"; int len = strlen(buf); char host[255]; char *p; int i; //to lower for(i = 0; i < len; i++) { if('A' <= buf[i] && 'Z' >= buf[i]) buf[i] |= 32; } //提出host中提供的URL p = strstr(buf, "host:"); p += 6; while(' ' == *p) p++; i = 0; while('\r' != *p && '\n' != *p && NULL != p) { host[i++] = *p++; } host[i] = 0; if(0 == strcmp(host, virtal_uri)) send_http2(connf); else send_http1(connf); } 主函数 int main(int argc, char * argv[] ) { int res_socket[2]; int max_fd = 3; struct epoll_event event[100]; struct sockaddr_in client_addr; char buf[1024]; int len; res_socket[0] = socket_listen( "127.0.0.1", 80) ;//绑定80端口,经过localhost访问 res_socket[1] = socket_listen( "127.0.0.1", 1024) ;//绑定1024,经过127.0.0.1访问 make_socket_non_blocking(res_socket[0]); //设置为非阻塞 make_socket_non_blocking(res_socket[1]); int epfd = epoll_init(max_fd); //初始化epoll epoll_handler_array(epfd, res_socket, 2); //epoll关联操做 while(1) { int count = epoll_wait(epfd, event, 2, -1); while(count--) { int connfd; //针对不一样的端口,便是不一样的网站进行不一样的处理 if( event[count].data.fd == res_socket[0]) { //当为默认端口的时候,须要添加虚拟端口处理方法。 connfd = accept(event[count].data.fd, (struct sockaddr *)&client_addr, &len); read(connfd, buf, 1024); virtual_port_handler(buf, connfd); } else { connfd = accept(event[count].data.fd, (struct sockaddr *)&client_addr, &len); send_http2(connfd); } close(connfd); } } }
完整代码: 网站
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/stat.h> #include <netinet/in.h> #include <arpa/inet.h> #include <fcntl.h> #include <sys/types.h> #include <unistd.h> #include <errno.h> #include <sys/epoll.h> /*设这文件句柄sfd为非阻塞 * */ static int make_socket_non_blocking (int sfd) { int flags, s; flags = fcntl (sfd, F_GETFL, 0); if (flags == -1) { perror ("fcntl"); return -1; } flags |= O_NONBLOCK; s = fcntl (sfd, F_SETFL, flags); if (s == -1) { perror ("fcntl"); return -1; } return 0; } /*建立epoll管理最大文件句柄的个数 *parameter * @maxfds:最大的句柄个数。也就是网站数目。端口的数目,应该多一点,用来处理接受的链接。 */ int epoll_init(int maxfds) { return epoll_create(maxfds); } /*设这epoll管理每一个文件句柄的参数和方法 *parameter * @fd:要管理socket文件句柄 * @maxfds:管理socket文件句柄的个数 */ static struct epoll_event * epoll_event_init(int * fd, int maxfds) { struct epoll_event *events; int i = 0; if(0 >= maxfds || NULL ==fd) return NULL; events = (struct epoll_event *)malloc( sizeof(struct epoll_event) * maxfds); for(; i < maxfds; i++) { events[i].data.fd = fd[i]; events[i].events = EPOLLIN | EPOLLET; } return events; } int epoll_handler_array(int epfd, int * fd, int maxfds) { struct epoll_event *events = epoll_event_init(fd, maxfds); struct epoll_event *ev = events; int i = 0; for(; i < maxfds; i++) { epoll_ctl(epfd, EPOLL_CTL_ADD, fd[i], ev); ev++; } } int epoll_handler_single(int epfd, int fd) { struct epoll_event *events; events = (struct epoll_event *)malloc( sizeof(struct epoll_event) ); events->events = EPOLLIN | EPOLLET; epoll_ctl(epfd, EPOLL_CTL_ADD, fd, events); } /* @description:开始服务端监听 @parameter ip:web服务器的地址 port:web服务器的端口 @result:成功返回建立socket套接字标识,错误返回-1 */ int socket_listen( char *ip, unsigned short int port) { int res_socket; //返回值 int res, on; struct sockaddr_in address; struct in_addr in_ip; res = res_socket = socket(AF_INET, SOCK_STREAM, 0); setsockopt(res_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); memset(&address, 0, sizeof(address)); address.sin_family = AF_INET ; address.sin_port =htons(port); address.sin_addr.s_addr = htonl(INADDR_ANY); //inet_addr("127.0.0.1"); res = bind( res_socket, (struct sockaddr *) &address, sizeof( address ) ); if(res) { printf( "port is used , not to repeat bind\n" ); exit(101); }; res = listen(res_socket,5); if(res) { printf( "listen port is error ;\n" ); exit( 102 ); }; return res_socket ; } void send_http1(int conn_socket) { char *send_buf = "HTTP/1.1 200 OK\r\nServer: Reage webserver\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><title>epoll learn</title></head><body><h1>Reage Test111111</h1>This is accessed by localhost</body></html>\r\n\r\n"; write(conn_socket, send_buf, strlen(send_buf)); } void send_http2(int conn_socket) { char *send_buf = "HTTP/1.1 200 OK\r\nServer: Reage webserver\r\nContent-Type: text/html\r\nConnection: close\r\n\r\n<!DOCTYPE html><html><head><title>epoll learn</title></head><body><h1>Reage Test22222</h1>This is accessed by 127.0.0.1 </body></html>\r\n\r\n"; write(conn_socket, send_buf, strlen(send_buf)); } void virtual_port_handler(char *buf, int connf) { char virtal_uri[] = "127.0.0.1"; int len = strlen(buf); char host[255]; char *p; int i; //to lower for(i = 0; i < len; i++) { if('A' <= buf[i] && 'Z' >= buf[i]) buf[i] |= 32; } p = strstr(buf, "host:"); p += 6; while(' ' == *p) p++; i = 0; while('\r' != *p && '\n' != *p && NULL != p) { host[i++] = *p++; } host[i] = 0; if(0 == strcmp(host, virtal_uri)) send_http2(connf); else send_http1(connf); } int main(int argc, char * argv[] ) { int res_socket[2]; int max_fd = 3; struct epoll_event event[100]; struct sockaddr_in client_addr; char buf[1024]; int len; res_socket[0] = socket_listen( "127.0.0.1", 80) ; res_socket[1] = socket_listen( "127.0.0.1", 1024) ; make_socket_non_blocking(res_socket[0]); make_socket_non_blocking(res_socket[1]); int epfd = epoll_init(max_fd); epoll_handler_array(epfd, res_socket, 2); while(1) { int count = epoll_wait(epfd, event, 2, -1); while(count--) { int connfd; //针对不一样的端口,便是不一样的网站进行不一样的处理 if( event[count].data.fd == res_socket[0]) { connfd = accept(event[count].data.fd, (struct sockaddr *)&client_addr, &len); read(connfd, buf, 1024); virtual_port_handler(buf, connfd); } else { connfd = accept(event[count].data.fd, (struct sockaddr *)&client_addr, &len); send_http2(connfd); } close(connfd); } } }blog地址: http://blog.csdn.net/rentiansheng/article/details/8722807