muduo只支持Linux2.6.x下的并发非阻塞TCP网络编程,它的核心是每个IO线程一个事件循环,把IO事件分发到回调函数上。
muduo把以前调用recv(2)来接收数据,调用accept(2)来接收新连接,调用send(2)发送数据转换为注册一个收数据的回调,网络库收到数据就回调我,直接把数据提供给我;注册一个接收连接的回调,网络库接收新的连接会回调我,直接把新的连接对象传给我;需要发送数据的时候,只管往连接中写,网络库会负责无阻塞的发送。
TCP网络编程本质是处理三个半事件:
1、建立连接。
2、断开连接。
3、消息到达,文件描述符可读。
3.5、消息发送完毕。
//echo服务实现
class EchoServer
{
public:
EchoServer(muduo::net::EventLoop* loop,
const muduo::net::InetAddress& listenAddr);
void start(); // calls server_.start();
private:
void onConnection(const muduo::net::TcpConnectionPtr& conn);
void onMessage(const muduo::net::TcpConnectionPtr& conn,
muduo::net::Buffer* buf,
muduo::Timestamp time);
muduo::net::TcpServer server_;
};
//在构造函数里注册回调函数
EchoServer::EchoServer(muduo::net::EventLoop* loop,
const muduo::net::InetAddress& listenAddr)
: server_(loop, listenAddr, "EchoServer")
{
server_.setConnectionCallback(
std::bind(&EchoServer::onConnection, this, _1));
server_.setMessageCallback(
std::bind(&EchoServer::onMessage, this, _1, _2, _3));
}
void EchoServer::onConnection(const muduo::net::TcpConnectionPtr& conn)
{
LOG_INFO << "EchoServer - " << conn->peerAddress().toIpPort() << " -> "
<< conn->localAddress().toIpPort() << " is "
<< (conn->connected() ? "UP" : "DOWN");
}
void EchoServer::onMessage(const muduo::net::TcpConnectionPtr& conn,
muduo::net::Buffer* buf,
muduo::Timestamp time)
{
muduo::string msg(buf->retrieveAllAsString());
LOG_INFO << conn->name() << " echo " << msg.size() << " bytes, "
<< "data received at " << time.toString();
conn->send(msg);
}
finger服务实现
1、拒绝连接。什么都不做,程序空等。
#include "muduo/net/EventLoop.h"
using namespace muduo;
using namespace muduo::net;
int main()
{
EventLoop loop;
loop.loop();
}
2、接受新连接。在1079端口侦听新连接,接受连接之后什么都不做,程序空等,muduo会自动丢弃收到的数据。
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"
using namespace muduo;
using namespace muduo::net;
int main()
{
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.start();
loop.loop();
}
3、主动断开连接,接受新连接之后主动断开。
include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"
using namespace muduo;
using namespace muduo::net;
void onConnection(const TcpConnectionPtr& conn)
{
if (conn->connected())
{
conn->shutdown();
}
}
int main()
{
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.setConnectionCallback(onConnection);
server.start();
loop.loop();
}
4、读取用户名,然后断开连接。
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"
using namespace muduo;
using namespace muduo::net;
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
if (buf->findCRLF())
{
conn->shutdown();
}
}
int main()
{
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}
5、读取用户名,输出错误信息,然后断开连接。
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"
using namespace muduo;
using namespace muduo::net;
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
if (buf->findCRLF())
{
conn->send("No such user\r\n");
conn->shutdown();
}
}
int main()
{
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}
6、从空的UserMap里查找用户。
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"
#include <map>
using namespace muduo;
using namespace muduo::net;
typedef std::map<string, string> UserMap;
UserMap users;
string getUser(const string& user)
{
string result = "No such user";
UserMap::iterator it = users.find(user);
if (it != users.end())
{
result = it->second;
}
return result;
}
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
const char* crlf = buf->findCRLF();
if (crlf)
{
string user(buf->peek(), crlf);
conn->send(getUser(user) + "\r\n");
buf->retrieveUntil(crlf + 2);
conn->shutdown();
}
}
int main()
{
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}
7、在UserMap里添加一个用户。
#include "muduo/net/EventLoop.h"
#include "muduo/net/TcpServer.h"
#include <map>
using namespace muduo;
using namespace muduo::net;
typedef std::map<string, string> UserMap;
UserMap users;
string getUser(const string& user)
{
string result = "No such user";
UserMap::iterator it = users.find(user);
if (it != users.end())
{
result = it->second;
}
return result;
}
void onMessage(const TcpConnectionPtr& conn,
Buffer* buf,
Timestamp receiveTime)
{
const char* crlf = buf->findCRLF();
if (crlf)
{
string user(buf->peek(), crlf);
conn->send(getUser(user) + "\r\n");
buf->retrieveUntil(crlf + 2);
conn->shutdown();
}
}
int main()
{
users["schen"] = "Happy and well";
EventLoop loop;
TcpServer server(&loop, InetAddress(1079), "Finger");
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}
TCP长连接性能不错。