运行结果:

补充:
1、通信套接字
cpp
static void HandleRequest(Connection* conn)
{
string s;
while(DeLenHeader(conn->_inbuffer, &s))
{
Request req;
req.DeSerialize(s);
int result;
switch(req._op)
{
case '+':
result= req._x+ req._y;
break;
case '-':
result= req._x- req._y;
break;
case '/':
result= req._x/ req._y;
break;
case '*':
result= req._x* req._y;
break;
}
Response rsp(result, 0);
string sen= rsp.Serialize();
EnLenHeader(sen);
conn->_outbuffer+= sen;
}
if(!conn->_outbuffer.empty())
{
conn->_server->ModifyEvents(conn->_fd, EPOLLIN | EPOLLOUT| EPOLLET);
}
}
static void HandleRead(Connection* conn)
{
std::string& inbuffer= conn->_inbuffer;
char buffer[1024];
while(1)
{
int n= read(conn->_fd, buffer, sizeof(buffer)-1);
if(n> 0)
{
buffer[n]= 0;
inbuffer+= buffer;
}
else if(n== 0)
{
conn->_server->DelConnection(conn);
conn->_server->DelEvents(conn->_fd);
close(conn->_fd);
delete conn;
return;
}
else if(n== -1 && errno== EAGAIN)
{
break;
}
}
HandleRequest(conn);
}
static void HandleWrite(Connection* conn)
{
while(1)
{
int n= write(conn->_fd, conn->_outbuffer.c_str(), conn->_outbuffer.size());//参数传的是要写的数据,返回值是实际写入发送缓冲区的数据字节数
if(n> 0)
{
conn->_outbuffer.erase(0, n);
if(conn->_outbuffer.empty())
{
break;
}
}
else if(n==-1 && errno== EAGAIN)
{
break;
}
}
//走到这里,可能是数据全部写进了发送缓冲区,也可能是发送缓冲区满了
//如果是因为全写进了发送缓冲区,那么就不需要监控可写事件了,如果是发送缓冲区满了,那就还得监控,等发送缓冲区的数据由内核发送出去后,会执行ep_poll_callback,将struct epitem加进就绪队列里
if(conn->_outbuffer.empty())
{
conn->_server->ModifyEvents(conn->_fd, EPOLLIN |EPOLLET);
}
}
如果我们往发送缓冲区中一次写很多数据,那么很可能最后只能写入一部分,然后write会返回写入发送缓冲区的数据的字节数,如果写是非阻塞的,那么当发送缓冲区满了的时候,write会直接返回-1,设置errno为EAGAIN
上面的代码中,当对接受缓冲区中的数据接收并处理过之后,会将结果数据保存在另一个缓冲区中,然后启动可写事件监控,当结果数据没了之后,那就关闭可写事件监控
2、epoll_ctl
epoll_ctl有三种操作
-
EPOLL_CTL_ADD :用于添加新的文件描述符,如果已有对应文件描述符则添加失败
-
EPOLL_CTL_MOD :用于修改已监控文件描述符的事件(覆盖式)
-
EPOLL_CTL_DEL :用于移除文件描述符的监控