该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] = '