创建套接字
绑定
监听
创建event_base根节点
初始化上树节点 lfd
上树
循环监听
收尾
普通的event事件 文件描述符 事件(底层缓冲区的读事件或者写事件) 触发 回调
高级的event事件 bufferevent事件
核心: 一个文件描述符 两个缓冲区 3个回调
读写缓冲区,读回调,写回调,事件回调,一个文件描述符,
改变了事件触发回调,设置完自动上树,设置事件使能和非使能,就可以让一个事件实现某种功能,
bufferevent事件的API
创建新的节点
struct bufferevent *bufferevent_socket_new(struct event_base *base, evutil_socket_t fd, int options);
参数:
base : event_base 根节点
fd: 要初始化上树的文件描述符
options :
BEV_OPT_CLOSE_ON_FREE -- 释放bufferevent自动关闭底层接口
BEV_OPT_THREADSAFE -- 使bufferevent能够在多线程下是安全的
返回值:
新建节点的地址
设置节点的回调
释放bufferevent
void bufferevent_setcb(struct bufferevent *bufev,
bufferevent_data_cb readcb, bufferevent_data_cb writecb,
bufferevent_event_cb eventcb, void *cbarg);
参数:
bufev : 新建的节点的地址
readcb : 读回调
writecb : 写回调
eventcb : 异常回调
cbarg: 传给回调函数的参数
typedef void (*bufferevent_data_cb)(struct bufferevent *bev, void *ctx);// 读写回调
typedef void (*bufferevent_event_cb)(struct bufferevent *bev, short what, void *ctx);//事件回调
BEV_EVENT_EOF, 对方关闭连接
BEV_EVENT_ERROR,出错
BEV_EVENT_TIMEOUT,超时
BEV_EVENT_CONNECTED 建立连接成功
让事件使能
int bufferevent_enable(struct bufferevent *bufev, short event);//EV_READ EV_WRITE
int bufferevent_disable(struct bufferevent *bufev, short event);//EV_READ EV_WRITE
发送数据
int bufferevent_write(struct bufferevent *bufev, const void *data, size_t size);
bufferevent_write是将data的数据写到bufferevent的写缓冲区
接收数据
size_t bufferevent_read(struct bufferevent *bufev, void *data, size_t size);
bufferevent_read 是将bufferevent的读缓冲区数据读到data中,同时将读到的数据从bufferevent的读缓冲清除。
创建套接字 绑定 监听 提取
struct evconnlistener *evconnlistener_new_bind(struct event_base *base,
evconnlistener_cb cb, void *ptr, unsigned flags, int backlog,
const struct sockaddr *sa, int socklen);
参数:
base : base根节点
cb : 提取cfd后调用的回调
ptr : 传给回调的参数
flags :
LEV_OPT_LEAVE_SOCKETS_BLOCKING 文件描述符为阻塞的
LEV_OPT_CLOSE_ON_FREE 关闭时自动释放
LEV_OPT_REUSEABLE 端口复用
LEV_OPT_THREADSAFE 分配锁,线程安全
backlog : -1
sa : 绑定的地址信息
socklen : sa的大小
返回值: 连接侦听器的地址
回调
typedef void (*evconnlistener_cb)(struct evconnlistener *evl, evutil_socket_t fd, struct sockaddr *cliaddr, int socklen, void *ptr);
参数:
evl : 链接侦听器的地址
fd : cfd
cliaddr: 客户端的地址信息
ptr: evconnlistener_new_bind传过来的参数
struct bufferevent *bufferevent_socket_new(struct event_base *base,-1, int options);
int bufferevent_socket_connect(struct bufferevent *bev, struct sockaddr *serv, int socklen);
bev: 新建的节点
serv: 服务器的地址信息
socklen: serv长度
网络地址和端口通过http协议 ,进行解析请求找到浏览器请求的文件,没找到返回状态码404,根据域名也可以解析通过DNS解析
html 超文本标签语句(超文本标记语言)
<><>
HTTP协议
http请求
请求行: GET /demo.html HTTP/1.1\r\n
请求方式 /请求的内容 版本\r\n
请求头
空行
\r\n
数据
200 OK 客户端请求成功
301 Moved Permanently 重定向
400 Bad Request 客户端请求有语法错误,不能被服务器所理解
401 Unauthorized 请求未经授权,这个状态代码必须和WWW-Authenticate报头域一起使用
403 Forbidden 服务器收到请求,但是拒绝提供服务
404 Not Found 请求资源不存在,eg:输入了错误的URL
500 Internal Server Error 服务器发生不可预期的错误
503 Server Unavailable 服务器当前不能处理客户端的请求,一段时间后可能恢复正常
struct dirent {
ino_t d_ino; /* inode number */
off_t d_off; /* not an offset; see NOTES */
unsigned short d_reclen; /* length of this record */
unsigned char d_type; /* type of file; not supported
by all filesystem types */
char d_name[256]; /* filename */
};
scandir 读取目录下的文件
struct dirent **mylist : //指向指针数组的首元素的地址
int scandir(const char *dirp, struct dirent ***namelist,
int (*filter)(const struct dirent *),
int (*compar)(const struct dirent **, const struct dirent **));
参数:
dirp: 目录的路径名
namelist: mylist地址
filter: 过滤的函数入口地址
compar : 排序函数入口地址 写 alphasort(字母排序)
返回值: 读取文件的个数
[GET] [/%E8%8B%A6%E7%93%9C.txt] [HTTP/1.1]
char buf[128]={ 0xe8,0x8b,0xa6,0xe7,0x93,0x9c,'.','t','x','t'};
"e8" => 0xe8
'8' => '8'-'0' = 8
e = 'e' -'a'+10 =14
'e8' = ('e' -'a'+10)*16 + ('8'-'0')*1 = 0xe8
写缓存区可能满,写不进去,写不进去监听EPOLLOUT,将没有发送的数据保存,等写事件触发,写出去
消息存储未发送的数据
libevent编写tcp服务器流程创建套接字,绑定,监听,创建根节点,lfd,上树,循环监听,普通event事件文件描述符,事件触发回调,bufferevent读写缓冲区,读回调,写回调,事件回调,一个文件描述符
bufferevent改变了事件触发回调,设置完自动上树,设置事件使能和非使能,就可以让一个事件实现某种功能,知道初始化上树文件描述符,设置节点回调,设置事件使能,设置读写数据函数
连接侦听器 创建套接字,绑定监听提取,
创建套接字 buffer_event_new创建节点,
网络地址和端口通过http协议 ,进行解析请求找到浏览器请求的文件,没找到返回状态码404,根据域名也可以解析通过DNS解析
html超文本标签语句http协议请求行的代码不要忘记\r\n,get post一个明文传输
应答需要状态码显示回复内容,状态码一般需要知道200,404作用,需要知道整个流程,
要知道scandir函数的作用读取目录下的文件
有些中文需要处理,