1 回显功能
逻辑:将数据读到input_buf中---->将input_buf存到业务的msg内存中进行业务处理---->将业务数据msg写到output_buf中---->将output_buf中的数据写到客户端套接字connfd中
input_buf ibuf;
output_buf obuf;
int ret =0;
char *msg = NULL;
int msg_len = 0;
do{
ret = ibuf.read_data(connfd);
if(ret==-1){
fprintf(stderr, "ibuf read_data error\n");
break;
}
//将ibuf数据进行业务处理
msg_len = ibuf.length();
msg = (char*)malloc(msg_len);
ZeroMemory(msg, msg_len);
memcpy(msg, ibuf.data(), msg_len);
ibuf.pop(msg_len);
ibuf.adjust();
printf("recv data=%s\n", msg);
//将数据写到obuf
obuf.send_data(msg, msg_len);
while(obuf.length()){
int write_ret = obuf.write2fd(connfd);
if(write_ret==-1)
{
fprintf(stderr, "write2fd error\n");
return;
}
else if(write_ret==0){
continue;
}
}
free(msg);
}while(ret!=0);
//客户端已经关闭
close(connfd);
2 多路IO事件机制 event_loop (基于epoll原生事件来封装)
2.1 event_base
io_event:包含读回调及参数、写回调及参数
io_callback:事件的回调函数
/*
定义IO复用机制事件的封装(epoll原生事件封装)
*/
class event_loop;
//IO事件触发的回调函数
typedef void io_callback(event_loop *loop, int fd, void *args);
//封装一次IO触发的事件
struct io_event{
io_event(){
mask = 0;
write_callback = NULL;
read_callback = NULL;
wcb_args = NULL;
rcb_args = NULL;
}
//事件的读写属性
int mask; //EPOLLIN, EPOLLOUT
//读事件触发所绑定的回调函数
io_callback *read_callback;
//写事件触发所绑定的回调函数
io_callback *write_callback;
//读事件回调函数的形参
void *rcb_args;
//写事件回调函数形参
void *wcb_args;
};
2.2 event_loop
2.2.1 属性
_io_evs: <key, value>-------><fd, io_event>
listen_fd_set:正在被监听的fd集合
2.2.2 方法
add_io_event():添加一个事件
delete_io_event():删除一个事件
#define MAXEVENTS 10
//map:<key, value>------><fd, io_event>
typedef std::unordered_map<int, io_event> io_event_map;
typedef std::unordered_map<int, io_event>::iterator io_event_map_it;
//set: fd
typedef std::unordered_set<int> listen_fd_set;
class event_loop
{
public:
//创建epoll
event_loop();
//阻塞循环监听事件,并且处理
void event_process();
//添加一个io事件到event_pool中
void add_io_envent(int fd, io_callback *proc, int mask, void *args);
//删除一个io事件从event_pool中
void delete_io_event(int fd);
//删除一个io事件的某个触发条件(EPOLLIN/EPOOLOUT)
void del_io_event(int fd, int mask);
private:
int _epfd; //通过epoll_create创建
//当前event_loop监控的fd和对应事件的关系
io_event_map _io_evs; //关系表
//当前event_loop都有哪些fd正在监听[epoll_wait()正在等待哪些fd触发状态]
listen_fd_set listen_fd;
//每次epoll_wait所返回的是被激活的事件集合
struct epoll_event _fired_evs[MAXEVENTS];
};
3 LarsV0.3开发
tcp_server(添加一个event_loop属性;tcp_server创建完listen_fd之后,将listen_fd绑定一个回调业务的读事件)------------->>>调用accept_callback(accpet得到一个新的connfd;将connfd的读事件和读回调server_rd_callback添加到event_loop中)------------->>>server_rd_callback(读取客户端数据;将connfd读事件删除,添加写事件和写回调server_wt_callback到event_loop中)------------->>>server_wt_callback(将数据写回客户端;将connfd写事件删除,添加读事件和读回调server_rd_callback到event_loop中。
void accept_callback(event_loop* loop, int fd, void *args);
void server_wt_callback(event_loop *loop, int fd, void *args);
//临时的收发消息结构
struct message{
char data[m4k];
char len;
};
void accept_callback(event_loop* loop, int fd, void *args)
{
tcp_server *server = (tcp_server*)args;
server->do_accept();
}
//客户端connfd注册的写事件的回调业务
void server_wt_callback(event_loop *loop, int fd, void *args)
{
struct message *msg = (struct message*) args;
output_buf obuf;
//将msg加入到obuf
obuf.send_data(msg->data, msg->len);
while(obuf.length())
{
int write_num = obuf.write2fd(fd);
if(write_num==-1)
{
fprintf(stderr, "write connfd error\n");
return;
}
else if(write_num==0)
{
//当前不可写
break;
}
}
//删除写事件 添加读事件
loop->del_io_event(fd, EPOLLOUT);
loop->add_io_envent(fd, server_rd_callback, EPOLLIN, msg);
}
//客户端connfd注册的读事件的回调业务
void server_rd_callback(event_loop *loop, int fd, void *args)
{
struct message *msg = (struct message*) args;
int ret = 0;
input_buf ibuf;
ret = ibuf.read_data(fd);
if(ret==-1){
fprintf(stderr, "ibuf_read errror\n");
//当前的读事件删除
loop->delete_io_event(fd);
//关闭
close(fd);
return ;
}
if(ret==0)
{
//对方正常关闭,当前的读事件删除
loop->delete_io_event(fd);
close(fd);
return ;
}
//将读到的数据拷贝到msg中
msg->len = ibuf.length();
ZeroMemory(msg->data, msg->len);
memcpy(msg->data, ibuf.data(), msg->len);
ibuf.pop(msg->len);
ibuf.adjust();
printf("recv data = %s\n", msg->data);
//删除读事件,添加写事件
loop->del_io_event(fd, EPOLLIN);
loop->add_io_envent(fd, server_wt_callback, EPOLLOUT, msg); //epoll_wait会立刻触发EPOLLOUT事件
}