说明:
调用Connector类的start() ,新建socket非阻塞连接服务器;
调用Connector类的shutdown() ,关闭套接字的写管道;
调用Connector 类的stop() ,让epoll 不再关注套接字对应Channel 上的事件,将Channel从EPOLL类的channels_中移除,且从 epoll监听集合中移除;
TcpClient::newConnection中新建Socket以及对应的Channel,再将本层的函数
connectionCallback_/messageCallback_/writeCompleteCallback_注册给该Channel ;
TcpClient.h
#ifndef MUDUO_NET_TCPCLIENT_H
#define MUDUO_NET_TCPCLIENT_H
#include <boost/noncopyable.hpp>
#include <muduo/base/Mutex.h>
#include <muduo/net/TcpConnection.h>
namespace muduo
{
namespace net
{
class Connector;
typedef boost::shared_ptr<Connector> ConnectorPtr;
class TcpClient : boost::noncopyable
{
public:
// TcpClient(EventLoop* loop);
// TcpClient(EventLoop* loop, const string& host, uint16_t port);
TcpClient(EventLoop* loop,
const InetAddress& serverAddr,
const string& name);
~TcpClient(); // force out-line dtor, for scoped_ptr members.
void connect();
void disconnect();
void stop();
TcpConnectionPtr connection() const
{
MutexLockGuard lock(mutex_);
return connection_;
}
EventLoop* getLoop() const { return loop_; }
bool retry() const;
void enableRetry() { retry_ = true; }
/// Set connection callback.
/// Not thread safe.
void setConnectionCallback(const ConnectionCallback& cb)
{ connectionCallback_ = cb; }
/// Set message callback.
/// Not thread safe.
void setMessageCallback(const MessageCallback& cb)
{ messageCallback_ = cb; }
/// Set write complete callback.
/// Not thread safe.
void setWriteCompleteCallback(const WriteCompleteCallback& cb)
{ writeCompleteCallback_ = cb; }
private:
/// Not thread safe, but in loop
void newConnection(int sockfd);
/// Not thread safe, but in loop
void removeConnection(const TcpConnectionPtr& conn);
EventLoop* loop_;
ConnectorPtr connector_; // avoid revealing Connector
const string name_;
ConnectionCallback connectionCallback_;
MessageCallback messageCallback_;
WriteCompleteCallback writeCompleteCallback_;
bool retry_; // atmoic
bool connect_; // atomic
// always in loop thread
int nextConnId_;
mutable MutexLock mutex_;
TcpConnectionPtr connection_; // @BuardedBy mutex_
};
}
}
#endif // MUDUO_NET_TCPCLIENT_H
TcpClient.cc
#include <muduo/net/TcpClient.h>
#include <muduo/base/Logging.h>
#include <muduo/net/Connector.h>
#include <muduo/net/EventLoop.h>
#include <muduo/net/SocketsOps.h>
#include <boost/bind.hpp>
#include <stdio.h> // snprintf
using namespace muduo;
using namespace muduo::net;
// TcpClient::TcpClient(EventLoop* loop)
// : loop_(loop)
// {
// }
// TcpClient::TcpClient(EventLoop* loop, const string& host, uint16_t port)
// : loop_(CHECK_NOTNULL(loop)),
// serverAddr_(host, port)
// {
// }
namespace muduo
{
namespace net
{
namespace detail
{
void removeConnection(EventLoop* loop, const TcpConnectionPtr& conn)
{
loop->queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn));
}
void removeConnector(const ConnectorPtr& connector)
{
//connector->
}
}
}
}
/*
初始化要连接的服务器的addr
*/
TcpClient::TcpClient(EventLoop* loop,
const InetAddress& serverAddr,
const string& name)
: loop_(CHECK_NOTNULL(loop)),
connector_(new Connector(loop, serverAddr)),
name_(name),
connectionCallback_(defaultConnectionCallback),
messageCallback_(defaultMessageCallback),
retry_(false),
connect_(true),
nextConnId_(1)
{
connector_->setNewConnectionCallback(
boost::bind(&TcpClient::newConnection, this, _1));
// FIXME setConnectFailedCallback
LOG_INFO << "TcpClient::TcpClient[" << name_
<< "] - connector " << get_pointer(connector_);
}
TcpClient::~TcpClient()
{
LOG_INFO << "TcpClient::~TcpClient[" << name_
<< "] - connector " << get_pointer(connector_);
TcpConnectionPtr conn;
{
MutexLockGuard lock(mutex_);
conn = connection_;
}
if (conn)
{
// FIXME: not 100% safe, if we are in different thread
CloseCallback cb = boost::bind(&detail::removeConnection, loop_, _1);
loop_->runInLoop(
boost::bind(&TcpConnection::setCloseCallback, conn, cb));
}
else
{
connector_->stop();
// FIXME: HACK
loop_->runAfter(1, boost::bind(&detail::removeConnector, connector_));
}
}
/*
调用Connector 类的start() ,新建socket 非阻塞连接服务器
*/
void TcpClient::connect()
{
// FIXME: check state
LOG_INFO << "TcpClient::connect[" << name_ << "] - connecting to "
<< connector_->serverAddress().toIpPort();
connect_ = true;
connector_->start();
}
/*
调用Connector 类的shutdown() ,关闭套接字的写管道
*/
void TcpClient::disconnect()
{
connect_ = false;
{
MutexLockGuard lock(mutex_);
if (connection_)
{
connection_->shutdown();
}
}
}
/*
调用Connector 类的stop() ,
让epoll 不再关注套接字对应Channel 上的事件;
将Channel 从EPOLL类的channels_ 中移除,且从epoll监听集合中移除;
*/
void TcpClient::stop()
{
connect_ = false;
connector_->stop();
}
/*
new TcpConnection 即新建Socket以及对应的Channel,
再将本层的函数connectionCallback_/messageCallback_/writeCompleteCallback_
注册给该Channel ;
*/
void TcpClient::newConnection(int sockfd)
{
loop_->assertInLoopThread();
InetAddress peerAddr(sockets::getPeerAddr(sockfd));
char buf[32];
snprintf(buf, sizeof buf, ":%s#%d", peerAddr.toIpPort().c_str(), nextConnId_);
++nextConnId_;
string connName = name_ + buf;
InetAddress localAddr(sockets::getLocalAddr(sockfd));
// FIXME poll with zero timeout to double confirm the new connection
// FIXME use make_shared if necessary
TcpConnectionPtr conn(new TcpConnection(loop_,
connName,
sockfd,
localAddr,
peerAddr));
conn->setConnectionCallback(connectionCallback_);
conn->setMessageCallback(messageCallback_);
conn->setWriteCompleteCallback(writeCompleteCallback_);
conn->setCloseCallback(
boost::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe
{
MutexLockGuard lock(mutex_);
connection_ = conn;
}
conn->connectEstablished();
}
/*
TcpConnection::connectDestroyed里面即会调用
TcpClient::connectionCallback_函数
*/
void TcpClient::removeConnection(const TcpConnectionPtr& conn)
{
loop_->assertInLoopThread();
assert(loop_ == conn->getLoop());
{
MutexLockGuard lock(mutex_);
assert(connection_ == conn);
connection_.reset();
}
loop_->queueInLoop(boost::bind(&TcpConnection::connectDestroyed, conn));
if (retry_ && connect_)
{
LOG_INFO << "TcpClient::connect[" << name_ << "] - Reconnecting to "
<< connector_->serverAddress().toIpPort();
connector_->restart();
}
}