一、TcpConnection类
TcpConnection类用于管理Acceptor类接收到的每条连接,每当Acceptor类接收到一个新的连接时就创建一个TcpConnection类
每个TcpConnection类有一个唯一的name,每个TcpConnection对象创建时需要传入一个fd,并针对该fd创建一个Channel对象
注意:TcpConnection表示的是一次Tcp连接,它是不可再生的,一旦断开,这个TcpConnection就没啥用了。
TcpConnection::TcpConnection(EventLoop* loop,
const std::string& nameArg,
int sockfd,
const InetAddress& localAddr,
const InetAddress& peerAddr)
: loop_(CHECK_NOTNULL(loop)),
name_(nameArg),
state_(kConnecting),
socket_(new Socket(sockfd)),
channel_(new Channel(loop, sockfd)),
localAddr_(localAddr),
peerAddr_(peerAddr)
{
channel_->setReadCallback(std::bind(&TcpConnection::handleRead, this));
}
TcpConnection创建完成之后需要调用connectEstablished方法开始监测该Channel上的读事件
void TcpConnection::connectEstablished()
{
loop_->assertInLoopThread();
assert(state_ == kConnecting);
setState(kConnected);
channel_->enableReading();
connectionCallback_(shared_from_this()); //该回调通知上层调用者已建立好连接(即该连接已经可以开始接受读事件了)
}
当有可读事件时,表示该连接上有新的消息到来
void TcpConnection::handleRead()
{
char buf[65536];
ssize_t n = ::read(channel_->fd(), buf, sizeof buf);
messageCallback_(shared_from_this(), buf, n);
}
二、TcpServer类
TcpServer类用来统一管理Acceptor类和TcpConnection类,TcpServer类持有一个Acceptor类,它负责启动Acceptor类来开始监听本地的一个端口号
TcpServer::TcpServer(EventLoop* loop, const InetAddress& listenAddr)
: loop_(CHECK_NOTNULL(loop)),
name_(listenAddr.toHostPort()),
acceptor_(new Acceptor(loop, listenAddr)),
started_(false),
nextConnId_(1)
{
acceptor_->setNewConnectionCallback(std::bind(&TcpServer::newConnection, this, std::placeholders::_1, std::placeholders::_2));
}
启动acceptor对象开始监听
void TcpServer::start()
{
if (!started_)
{
started_ = true;
}
if (!acceptor_->listenning())
{
loop_->runInLoop(std::bind(&Acceptor::listen, acceptor_)); //此处acceptor_不要使用unique_ptr,首先编译就不会通过,只有移动语义,不能赋值
}
}
每当acceptor对象接收到一个新的连接时,TcpServer会在相应的回调函数中创一个TcpConnection,并给这个对象起一个唯一的name,然后启动TcpConnection开始监听读事件,最后把
void TcpServer::newConnection(int sockfd, const InetAddress& peerAddr)
{
loop_->assertInLoopThread();
char buf[32];
snprintf(buf, sizeof buf, "#%d", nextConnId_);
++nextConnId_;
std::string connName = name_ + buf; //给每个连接一个唯一的名字
InetAddress localAddr(sockets::getLocalAddr(sockfd));
TcpConnectionPtr conn(new TcpConnection(loop_, connName, sockfd, localAddr, peerAddr));
connections_[connName] = conn; //将插入map集合
conn->setConnectionCallback(connectionCallback_);
conn->setMessageCallback(messageCallback_);
conn->connectEstablished(); //开始监测channel上的读事件
}
TcpServer调用的一个示例如下:
void onConnection(const muduo::TcpConnectionPtr& conn)
{
if (conn->connected())
{
printf("onConnection(): new connection [%s] from %s\n", conn->name().c_str(), conn->peerAddress().toHostPort().c_str());
}
else
{
printf("onConnection(): connection [%s] is down\n", conn->name().c_str());
}
}
void onMessage(const muduo::TcpConnectionPtr& conn,
const char* data,
ssize_t len)
{
printf("onMessage(): received %zd bytes from connection [%s]\n", len, conn->name().c_str());
}
int main()
{
printf("main(): pid = %d\n", getpid());
muduo::InetAddress listenAddr(9981);
muduo::EventLoop loop;
muduo::TcpServer server(&loop, listenAddr);
server.setConnectionCallback(onConnection);
server.setMessageCallback(onMessage);
server.start();
loop.loop();
}
运行结果如下图: