本身動手寫web服務器之虛擬端口支持

爲何須要支持虛擬端口? 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
相關文章
相關標籤/搜索