为什么需要支持虚拟端口?
如果不支持虚拟端口,每一个ip只能对应一个网站。再对应别的域名就需要加端口了。
支持虚拟端口的原理??
首先,我们知道,当多个域名与一个ip相对。DNS只能提供ip地址,无法提供端口号。所以web browser无法知道多个域名与一个ip对应的时候那个域名应该使用哪个端口。当用户不能提供端口web browser只能使用80默认端口了。我们在DNS没法做人和作用。只能在web browser和web服务器上做手脚。web browser在发送request请求的时候,添加一个HOST项,web 服务器检查就可以了。
我就以将localhost和127.0.0.1对应不同的网站为例吧,可能不是很恰当,但是可以用来说明问题。如果向给好的话,可以通过修改host,将不同的域名对应到本地就行了。
下面主要代码:(本程序只是一个例子,只是用来说明原理,其中可有与实际开发中不允许的操作,也能会出现错误的,请大家谅解。本程序本人只在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
来源:oschina
链接:https://my.oschina.net/u/77406/blog/117811