本文共 10794 字,大约阅读时间需要 35 分钟。
http://blog.csdn.net/fangjian1204/article/details/34415651
http服务器已经可以处理并发连接,支持多个客户端并发访问,每个连接可以持续读写数据,当然,这只是一个简单的学习例子,还有很多bug,发表出来只是希望大家可以互相学习,我也在不断的改进,希望大家有什么意见可以多多指点,谢谢
server.h
-
-
-
-
-
-
-
-
- #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
-
-
-
-
-
-
-
- #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);
-
- 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("---创建监听结构体失败---\n");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\n");
- 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-------\n");
- 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\n");
- return;
- }
- web_connection_t* new_conn = NULL;
- initConnection(new_conn);
- if(new_conn == NULL){printf("---创建连接结构体失败---\n");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-------\n");
-
- 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("----数据读取完毕-----\n");
- break;
- }
- else if(len > 0)
- {
- conn->query_end_index += len;
- conn->query_remain_len-= len;
- }
- else if(len == 0)
- {
- printf("----连接关闭-----\n");
- 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," \t");
- if( !ptr)
- {
- printf("请求行解析失败\n");
- 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," \t");
- if( !ptr)
- {
- printf("请求行解析失败\n");
- 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,"\n");
- if(!ptr)
- {
- printf("请求行解析失败\n");
- 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,"\n");
- len = end_line - conn->querybuf - conn->query_start_index;
- if(len == 1)
- {
- printf("解析完毕\n");
- 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("----首部解析完毕----------\n");
- }
- void process_body(struct web_connection_t* conn)
- {
- if(conn->query_start_index == conn->query_end_index)
- {
- printf("---包体为空----\n");
- }
- else
- {
- printf("---丢体包体-----\n");
- }
- 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] = '\0';
-
- int filefd = open(path,O_RDONLY);
- if(filefd < 0)
- {
- cout << "无法打开该文件" <<endl;
- return ;
- }
- struct stat stat_buf;
- fstat(filefd,&stat_buf);
- sendfile(conn->fd,filefd,NULL,stat_buf.st_size);
- close(filefd);
-
-
-
- conn->state = READ;
- conn->read_event->handler = read_request;
- epoll_mod_event(conn,EPOLLIN | EPOLLERR);
-
-
- }
-
- void try_to_enlarge_buffer(struct web_connection_t& conn)
- {
- if(conn.query_remain_len < REMAIN_BUFFER)
- {
- int new_size = strlen(conn.querybuf) + QUERY_INIT_LEN;
- conn.querybuf = (char*)realloc(conn.querybuf,new_size);
- conn.query_remain_len = new_size - conn.query_end_index;
- }
- }
- void empty_event_handler(struct web_connection_t* conn)
- {
-
- }
-
- void close_conn( struct web_connection_t* conn )
- {
- static int count = 0;
- count ++;
- printf("关闭第%d个连接\n",count);
-
- close( conn->fd);
- free(conn->querybuf);
- free(conn->read_event);
- free(conn->write_event);
- free(conn);
- }
epoll_event.h
-
-
-
-
-
-
-
- #ifndef EVENT_H_
- #define EVENT_H_
-
- #include <netinet/in.h>
- #include "server.h"
- #define MAX_EVENT_NUMBER 10000
- #define QUERY_INIT_LEN 1024
- #define REMAIN_BUFFER 512
-
-
- #define ACCEPT 1
- #define READ 2
- #define QUERY_LINE 4
- #define QUERY_HEAD 8
- #define QUERY_BODY 16
- #define SEND_DATA 32
-
- struct web_connection_t;
-
- typedef void (*event_handler_pt)(web_connection_t* conn);
-
-
- struct web_event_t
- {
-
- unsigned write:1;
-
-
- unsigned accept:1;
-
- unsigned active:1;
- unsigned oneshot:1;
- unsigned eof:1;
- unsigned error:1;
-
- event_handler_pt handler;
- unsigned closed:1;
- };
-
- void epoll_init_event(web_connection_t* &conn);
- void epoll_add_event(web_connection_t* conn,int flag);
- void epoll_mod_event(web_connection_t* conn,int flag);
- void epoll_del_event(web_connection_t* conn);
- int ngx_epoll_process_events();
- #endif /* EVENT_H_ */
epoll_event.cpp
-
-
-
-
-
-
-
- #include "epoll_event.h"
- #include <sys/epoll.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
-
- static int ep = -1;
-
- void epoll_init_event(web_connection_t* &conn)
- {
- ep = epoll_create(1024);
- }
-
-
- void epoll_add_event(web_connection_t* conn,int flag)
- {
- epoll_event ee;
- int fd = conn->fd;
- ee.data.ptr = (void*)conn;
- ee.events = flag;
- epoll_ctl(ep,EPOLL_CTL_ADD,fd,&ee);
- }
-
-
- void epoll_mod_event(web_connection_t* conn,int flag)
- {
- epoll_event ee;
- int fd = conn->fd;
- ee.data.ptr = (void*)conn;
- ee.events = flag;
- epoll_ctl(ep,EPOLL_CTL_MOD,fd,&ee);
- }
-
-
- void epoll_del_event(web_connection_t* conn)
- {
- epoll_ctl( ep, EPOLL_CTL_DEL, conn->fd, 0 );
- }
-
- int ngx_epoll_process_events()
- {
- epoll_event event_list[MAX_EVENT_NUMBER];
- while(true)
- {
- int number = epoll_wait(ep,event_list,MAX_EVENT_NUMBER,-1);
-
- printf("number=%d\n",number);
- printf("当前进程ID为: %d \n",getpid());
-
- int i;
- for(i = 0;i < number;i++)
- {
- web_connection_t* conn = (web_connection_t*)(event_list[i].data.ptr);
- int socket = conn->fd;
-
- if ( event_list[i].events & EPOLLIN )
- {
- conn->read_event->handler(conn);
- }
-
- else if( event_list[i].events & EPOLLOUT )
- {
- conn->write_event->handler(conn);
- }
- else if( event_list[i].events & EPOLLERR )
- {
-
- }
- }
- }
- return 0;
- }
使用方法:
服务器使用方法:直接运行即可
客户端使用方法:编译客户端代码,然后 ./client 127.0.0.1 8083 5(最后一个代表客户端进程数)
本程序在linux平台下测试成功
免费代码下载地址: