这个版本更新主要是为了能使服务器能够同时处理多个请求。
最初有这个想法是因为这个博客最下面有一个select()函数,用来处理多个请求。之后又发现了epoll。发现了epoll之后本想写个小程序测试一下,但是却报了无法找到头文件的错误。这才意识到epoll是linux内核实现的,而我是用macOS开发的,macOS基于FreeBSD,也就是另一种类Unix系统。虽然都是类Unix系统,但是还是有些地方不一样,因此在这个环境下就用了kqueue,和epoll本质上是一样的,而且貌似用法要比epoll要简单。
这里有一篇比较系统的介绍epoll和kqueue之间的区别的文章。
据说kqueue只有三样东西:struct kevent结构体,EV_SET以及kevent函数。
struct kevent
结构体如下:
struct kevent {
uintptr_t ident; /* identifier for this event,标识符,比如该事件关联的文件描述符 */
int16_t filter; /* filter for event,过滤器,可以指定监听类型,如EVFILT_READ,EVFILT_WRITE,EVFILT_TIMER等 */
uint16_t flags; /* general flags ,可以指定事件操作类型,比如EV_ADD,EV_ENABLE, EV_DELETE等 */
uint32_t fflags; /* filter-specific flags */
intptr_t data; /* filter-specific data */
void *udata; /* opaque user data identifier,可以携带的任意数据 */
};
这个就类似于epoll中的epoll_event。
EV_SET
是一个用来初始化kevent函数的宏,其形式为:
EV_SET(&kev, ident, filter, flags, fflags, data, udata);
除了第一个参数以外,其他都和kevent中的成员相对应。
kevent函数
这个函数就是用来注册事件的,感觉像epoll_ctl和epoll_wait的结合。
其参数形式为:
int kevent(int kq,
const struct kevent *changelist, // 监视列表
int nchanges, // 监视列表长度
struct kevent *eventlist, // kevent函数用于返回已经就绪的事件列表
int nevents, // 返回的就绪事件的长度
const struct timespec *timeout); // 超时限制
另外注意:kevent与epoll最大的不同在于READ/WRITE事件是分开注册并且分开返回的,而Epoll则是一个fd一次返回读和写事件,用标志位来判断。
具体代码:
#include<cstdio>
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<unistd.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<sys/stat.h>
#include<sys/mman.h>
#include<sys/event.h>
#include<sys/time.h>
#include<fcntl.h>
#include"WebServer.h"
using namespace std;
bool is_get_http(char* request){
//判断是否为GET请求
return !strncmp(request,"GET",3);
}
char* get_file_name(char* buff){
//从请求中得到文件名
//printf("DEBUG:-----%s-----\n\n",buff);
if(buff==NULL||strlen(buff)<4)
return NULL;
char* fp=buff+4;
char* Space=strchr(fp,' ');
*Space='\0';
return fp;
}
int get_file_size(char* file_name){
//得到文件大小
if