tcpConnection
class TcpConnection : NonCopyable, public enable_shared_from_this
{
private:
enum StateE
{
k_disconnected,
k_connecting, //正在连接
k_connected, //已连接
k_disconnecting,
};
public:
TcpConnection(EventLoop *loop, const string name, int sockfd, const InetAddress &localaddr, const InetAddress &peeraddr);
~TcpConnection();
EventLoop *get_loop() const { return loop_; }
const string &get_name() const { return name_; }
const InetAddress &get_localaddr() const { return localaddr_; }
const InetAddress &get_peeraddr() const { return peeraddr_; }
bool connected() { return state_ == k_connected; }
void set_state(StateE state) { state_ = state; }
//发送数据
void send(const string& buf);
//断开连接
void shutdown();
//建立连接
void establish_connect();
//销毁连接
void destory_connect();
//设置回调
void set_close_callback(const CloseCallback &callback) { close_callback_ = callback; }
void set_highwater_callback(const HighWaterMarkCallback &callback) { highwater_callback_ = callback; }
void set_connection_callback(const ConnectionCallback &callback) { connection_callback_ = callback; }
void set_message_callback(const MessageCallback &callback) { message_callback_ = callback; }
void set_write_complete_callback(const WriteCompleteCallback &callback) { write_complete_callback_ = callback; }
private:
void handle_read(TimeStamp receive_time);
void handle_write();
void handle_close();
void handle_error();
void send_inLoop(const string& buf);
//void shutdown();
void shutdown_inLoop();
private:
EventLoop *loop_; //所属subloop,非baseloop
const string name_;
atomic_int state_;
bool reading_;
unique_ptr socket_;
unique_ptr channel_;
const InetAddress localaddr_;
const InetAddress peeraddr_;
ConnectionCallback connection_callback_; //有新连接时回调
MessageCallback message_callback_; //有读写消息的回调
WriteCompleteCallback write_complete_callback_; //消息发送完以后的回调
CloseCallback close_callback_;
HighWaterMarkCallback highwater_callback_;
size_t highwater_mark_; //高水位标志
Buffer input_buffer_; //接收数据的缓冲区
Buffer output_buffer_; //发送数据的缓冲区
};
static EventLoop *CheckLoopNotNull(EventLoop *loop)
{
if (loop == nullptr)
{
LOG_FATAL("%s:%s:%d tcpconnection is null \n", __FILE__, __FUNCTION__, __LINE__);
}
return loop;
}
TcpConnection::TcpConnection(EventLoop *loop, const string name, int sockfd, const InetAddress &localaddr, const InetAddress &peeraddr)
: loop_(CheckLoopNotNull(loop)), name_(name), state_(k_connecting), reading_(true), socket_(new Socket(sockfd)), channel_(new Channel(loop, sockfd)), localaddr_(localaddr), peeraddr_(peeraddr), highwater_mark_(64 * 1024 * 1024)
{
//给channel设置相应的回调函数,poller给channel通知感兴趣的事件发生了,channel会回调相应的操作函数s
channel_->set_readcallback(bind(&TcpConnection::handle_read, this, _1));
channel_->set_writecallback(bind(&TcpConnection::handle_write, this));
channel_->set_closecallback(bind(&TcpConnection::handle_close, this));
channel_->set_errorcallback(bind(&TcpConnection::handle_error, this));
LOG_INFO("tcp connection::ctor[%s] at fd = %d\n", name_.c_str(), sockfd);
socket_->set_keepAlive(true);
}
TcpConnection::~TcpConnection()
{
LOG_INFO("tcp connection::dtor[%s] at fd = %d state = %d \n", name_.c_str(), channel_->get_fd(), (int)state_);
}
//发送数据
void TcpConnection::send(const string &buf)
{
//必须是连接状态
if (state_ == k_connected)
{
//在所属loop所属的线程
if (loop_->is_in_loopThread())
{
send_inLoop(buf);
}
else
{
loop_->run_in_loop(bind(&TcpConnection::send_inLoop, this, buf));
}
}
}
//发送数据,应用写得快,内核发送的慢,我们需要把待发送数据写入缓冲区,而且设置了水位回调
void TcpConnection::send_inLoop(const string &buf)
{
ssize_t nwrote = 0;
size_t remaining = buf.size(); //未发送完数据的长度
bool fault_error = false;
//之前调用了shutdown
if (state_ == k_disconnected)
{
LOG_ERROR("disconnected,give up writing!\n");
return;
}
//channel第一次开始写数据,而且缓冲区无数据
if (!channel_->is_writting() && output_buffer_.readable_bytes() == 0)
{
nwrote = write(channel_->get_fd(), buf.c_str(), buf.size());
if (nwrote >= 0)
{
//发送成功
remaining = buf.size() - nwrote;
if (remaining == 0 && write_complete_callback_)
{
//数据一次发送完毕
loop_->queue_in_loop(bind(write_complete_callback_, shared_from_this()));
}
}
else
{
nwrote = 0;
//错误不是资源不可用
if (errno != EWOULDBLOCK)
{
LOG_ERROR("tcp connection::send in loop!\n");
//如果收到连接重置请求
if (errno == EPIPE || errno == ECONNRESET)
{
fault_error = true;
}
}
}
}
//当前write没有把数据全部发送出去,剩余数据需要保存到缓冲区,
//然后给channel注册epollout,poller发现tcp缓冲区仍有数据,会调用handle write
if (!fault_error && remaining > 0)
{
//目前发送缓冲区剩余的待发送的长度
size_t oldlen = output_buffer_.readable_bytes();
if (oldlen + remaining >= highwater_mark_ && oldlen < highwater_mark_)
{
loop_->queue_in_loop(bind(highwater_callback_, shared_from_this(), oldlen + remaining));
}
output_buffer_.append(buf.c_str() + nwrote, remaining);
if (!channel_->is_writting())
{
channel_->enable_writing(); //注册channel写事件,否则poller不会通知
}
}
}
//断开连接
void TcpConnection::shutdown()
{
if (state_ == k_connected)
{
set_state(k_disconnecting);
loop_->run_in_loop(bind(&TcpConnection::shutdown_inLoop, this));
}
}
void TcpConnection::shutdown_inLoop()
{
//当前outputbuffer 中数据 全部发送完
if (!channel_->is_writting())
{
socket_->shutdown_write(); //关闭写端 后续调用handle close
}
}
//建立连接
void TcpConnection::establish_connect()
{
set_state(k_connected);
channel_->tie(shared_from_this());
channel_->enable_reading(); //向poller注册channel的epollin事件
//新连接建立
connection_callback_(shared_from_this());
}
//销毁连接
void TcpConnection::destory_connect()
{
if (state_ == k_connected)
{
set_state(k_disconnected);
channel_->dis_enable_all(); //把channel所有感兴趣的事件,从poller中delete
}
channel_->remove(); //从poller中删除掉
}
void TcpConnection::handle_read(TimeStamp receive_time)
{
//从channel中读数据
int save_errno = 0;
ssize_t n = input_buffer_.readfd(channel_->get_fd(), &save_errno);
if (n > 0)
{
//已建立连接的用户,有可读事件发生了,调用用户传入的回调操作 onmessage
message_callback_(shared_from_this(), &input_buffer_, receive_time);
}
else if (n == 0) //客户端断开连接
{
handle_close();
}
else //错误
{
errno = save_errno;
LOG_ERROR("tcp connection::handle read\n");
handle_error();
}
}
void TcpConnection::handle_write()
{
//如果channel对写事件感兴趣
if (channel_->is_writting())
{
int save_errno = 0;
ssize_t n = output_buffer_.writefd(channel_->get_fd(), &save_errno);
if (n > 0)
{
output_buffer_.retrieve(n);
//发送完成
if (output_buffer_.readable_bytes() == 0)
{
channel_->dis_enable_writing();
if (write_complete_callback_)
{
loop_->queue_in_loop(bind(write_complete_callback_, shared_from_this()));
}
//如果正在关闭
if (state_ == k_disconnecting)
{
shutdown_inLoop();
}
}
}
else
{
LOG_ERROR("tcp connection::handle write\n");
}
}
else //不可写
{
LOG_ERROR("tcp connection fd=%d is down,no more send\n", channel_->get_fd());
}
}
void TcpConnection::handle_close()
{
LOG_INFO("fd=%d state=%d", channel_->get_fd(), (int)state_);
set_state(k_disconnected);
channel_->dis_enable_all();
TcpConnectionPtr connection_ptr(shared_from_this());
//执行关闭连接的回调
connection_callback_(connection_ptr);
//关闭连接的回调
close_callback_(connection_ptr);
}
void TcpConnection::handle_error()
{
int optval;
socklen_t optlen = sizeof(optval);
int err = 0;
if (getsockopt(channel_->get_fd(), SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0)
{
//出错
err = errno;
}
else
{
err = optval;
}
LOG_ERROR("tcp connection handle error name:%s SO_ERROR:%d\n", name_.c_str(), err);
}