该httpserver已经能够处理并发连接,支持多个client并发訪问,每一个连接能够持续读写数据。当然。这仅仅是一个简单的学习样例。还有非常多bug,发表出来仅仅是希望大家能够互相学习。我也在不断的改进,希望大家有什么意见能够多多指点,谢谢
server.h
/* * server.h * * Created on: Jun 23, 2014 * Author: fangjian */ #ifndef SERVER_H_ #define SERVER_H_ #include "epoll_event.h" struct web_event_t; struct web_connection_t { int fd; int state;//当前处理到哪个阶段 struct web_event_t* read_event; struct web_event_t* write_event; char* querybuf; int query_start_index;//请求数据的当前指针 int query_end_index;//请求数据的下一个位置 int query_remain_len;//可用空间 char method[8]; char uri[128]; char version[16]; char host[128]; char accept[128]; char conn[20]; }; struct server { int epollfd; }; void web_epoll_ctl(int epollfd,int ctl,int fd,int flag); int setnonblocking(int fd); void initConnection(web_connection_t* &conn); void web_accept(struct web_connection_t* conn); void read_request( struct web_connection_t* conn ); void process_request_line(struct web_connection_t* conn); void process_head(struct web_connection_t* conn); void process_body(struct web_connection_t* conn); void send_response(struct web_connection_t* conn); void try_to_enlarge_buffer(struct web_connection_t& conn); void empty_event_handler(struct web_connection_t* conn); void close_conn( struct web_connection_t* conn ); #endif /* SERVER_H_ */
server.cpp
/* * server.cpp * * Created on: Jun 23, 2014 * Author: fangjian */ #include "server.h" #include "epoll_event.h" #include <stdio.h> #include <netinet/in.h> #include <arpa/inet.h> #include <string.h> #include <stdlib.h> #include <fcntl.h> #include<signal.h> #include <sys/socket.h> #include <sys/epoll.h> #include <sys/stat.h> #include <sys/sendfile.h> #include <iostream> using namespace std; int main(int argc,char* argv[]) { const char* ip = "127.0.0.1"; int port = 8083; signal(SIGPIPE,SIG_IGN);//原因:http://blog.sina.com.cn/s/blog_502d765f0100kopn.html int listenfd = socket(AF_INET,SOCK_STREAM,0); struct sockaddr_in address; bzero(&address,sizeof(address)); address.sin_family = AF_INET; inet_pton(AF_INET,ip,&address.sin_addr); address.sin_port = htons(port); bind(listenfd,(struct sockaddr*)&address,sizeof(address)); listen(listenfd,50); web_connection_t* conn = NULL; epoll_init_event(conn); initConnection(conn);//创建一个用于接受连接的结构体 if(conn == NULL){printf("---创建监听结构体失败--- ");return -1;};//创建监听结构体 conn->fd = listenfd; conn->read_event->handler = web_accept; epoll_add_event(conn,EPOLLIN | EPOLLERR); setnonblocking(listenfd); fork(); ngx_epoll_process_events();//进入事件循环。等待事件到达 } void initConnection(web_connection_t* &conn) { conn = (web_connection_t*)malloc(sizeof(web_connection_t)); conn->read_event = (web_event_t*)malloc(sizeof(web_event_t)); conn->write_event = (web_event_t*)malloc(sizeof(web_event_t)); conn->state = ACCEPT; conn->querybuf = (char*)malloc(QUERY_INIT_LEN); if(!conn->querybuf) { printf(" malloc error "); return; } conn->query_start_index = 0; conn->query_end_index = 0; conn->query_remain_len = QUERY_INIT_LEN; } int setnonblocking(int fd) { int old_option = fcntl(fd,F_GETFL); int new_option = old_option | O_NONBLOCK; fcntl(fd,F_SETFL,new_option); return old_option; } void web_accept(web_connection_t* conn) { printf("-----------accept------- "); struct sockaddr * client_address; socklen_t client_addrlength = sizeof(client_address); int connfd = accept(conn->fd,(struct sockaddr*)&(client_address),&client_addrlength); if(connfd == -1) { printf("accept error "); return; } web_connection_t* new_conn = NULL; initConnection(new_conn);//创建一个新的连接结构体 if(new_conn == NULL){printf("---创建连接结构体失败--- ");return;}; new_conn->fd = connfd; new_conn->state = READ; new_conn->read_event->handler = read_request; epoll_add_event(new_conn,EPOLLIN | EPOLLERR); setnonblocking(connfd); } void read_request( struct web_connection_t* conn ) { printf("-----------read_begin------- "); int len,fd = conn->fd; while(true) { /* 尝试添加缓冲区空间 */ try_to_enlarge_buffer(*conn); len= recv(fd,conn->querybuf + conn->query_end_index,conn->query_remain_len,0); if(len < 0) { printf("----数据读取完成----- "); break;//表示当前数据读取完成,不是出错 } else if(len > 0) { conn->query_end_index += len; conn->query_remain_len-= len; } else if(len == 0) { printf("----连接关闭----- "); epoll_del_event(conn); close_conn(conn ); return ; } } cout << "-----客户端的内容是 " << endl; cout << conn->querybuf << endl; process_request_line(conn); return ; } void process_request_line(struct web_connection_t* conn) { int len; char* ptr = strpbrk(conn->querybuf + conn->query_start_index," "); if( !ptr) { printf("请求行解析失败 "); return; } len = ptr - conn->querybuf - conn->query_start_index; strncpy(conn->method,conn->querybuf + conn->query_start_index,len); cout <<"metnod="<<conn->method<<endl; conn->query_start_index += (len+1); ptr = strpbrk(conn->querybuf + conn->query_start_index," "); if( !ptr) { printf("请求行解析失败 "); return; } len = ptr - conn->querybuf - conn->query_start_index; strncpy(conn->uri,conn->querybuf + conn->query_start_index,len); cout << "uri="<<conn->uri<<endl; conn->query_start_index += (len+1); ptr = strpbrk(conn->querybuf," ");//先是回车 ,再是换行 if(!ptr) { printf("请求行解析失败 "); return; } len = ptr - conn->querybuf - conn->query_start_index; strncpy(conn->version,conn->querybuf + conn->query_start_index,len); cout << "version="<<conn->version<<endl; conn->query_start_index += (len+1); cout <<"-----请求行解析完成----------"<<endl; process_head(conn); } void process_head(struct web_connection_t* conn) { cout << "-------開始解析首部------" << endl; char* end_line; int len; while(true) { end_line = strpbrk(conn->querybuf + conn->query_start_index," "); len = end_line - conn->querybuf - conn->query_start_index; if(len == 1) { printf("解析完成 "); conn->query_start_index += (len +1); cout << conn->querybuf + conn->query_start_index << endl; break; } else { if(strncasecmp(conn->querybuf+conn->query_start_index,"Host:",5) == 0) { strncpy(conn->host,conn->querybuf+conn->query_start_index + 6,len-6); cout << "host="<<conn->host<<endl; } else if(strncasecmp(conn->querybuf+conn->query_start_index,"Accept:",7) == 0) { strncpy(conn->accept,conn->querybuf+conn->query_start_index + 8,len-8); cout <<"accept="<<conn->accept <<endl; } else if(strncasecmp(conn->querybuf+conn->query_start_index,"Connection:",11) == 0) { strncpy(conn->conn,conn->querybuf+conn->query_start_index + 12,len-12); cout <<"connection="<<conn->conn <<endl; } else { } conn->query_start_index += (len +1); } } process_body(conn); printf("----首部解析完成---------- "); } void process_body(struct web_connection_t* conn) { if(conn->query_start_index == conn->query_end_index) { printf("---包体为空---- "); } else { printf("---丢体包体----- "); } conn->query_start_index = conn->query_end_index = 0; conn->state = SEND_DATA; conn->write_event->handler = send_response; conn->read_event->handler = empty_event_handler;//读事件回调函数设置为空 epoll_mod_event(conn,EPOLLOUT | EPOLLERR); } void send_response(struct web_connection_t* conn) { char path[128] = "http";//根文件夹下的文件夹 int len = strlen(conn->uri); memcpy(path+4,conn->uri,len); len += 4; path[len] = '