重写muduo之TcpConnection

目录

1、 TcpConnection.h

2、 TcpConnection.cc


1、 TcpConnection.h

TcpConnection底层绑定(管理)了一个Channel,Channel有事件被Poller通知后,会调用相应的回调,这些回调也是TcpConnection中包含的方法,将这些方法绑定了一下塞给channel作为回调,如果TcpConnection相应的底层对应的channel还在poller上注册着,还会感知到poller通知的事件,并且调用相应的回调,如果此时它对应的TcpConnection对象没有了(被人remove掉)怎么办?

tie使用弱智能指针记录,在处理事件的时候(handleEvent),肯定是被tie过,在这个方法里面将弱智能指针提升一下,如果不做任何的回调调用就说明TcpConnection这个对象已经没有了。

#pragma once
#include "noncopyable.h"
#include "InetAddress.h"
#include "Callbacks.h"
#include "Buffer.h"#include <memory>
#include <string>
#include <atomic>class Channel;
class EventLoop;
class Socket;/*** TcpServer => Acceptor => 有一个新用户连接,通过accept函数拿到connfd* * => TcpConnection 设置回调 =》 Channel => Poller =>Channel的回调操作* 
*/
class TcpConnection:noncopyable,public std::enable_shared_from_this<TcpConnection>//获得当前对象的智能指针
{
public:TcpConnection(EventLoop* loop,const std::string& name,int sockfd,const InetAddress& localAddr,const InetAddress& peerAddr);~TcpConnection();EventLoop* getLoop() const {return loop_;}const std::string& name() const{return name_;}const InetAddress& localAddress() const {return localAddr_;}const InetAddress& peerAddress() const {return peerAddr_;}bool connected() const {return state_==kConnected;}//发送数据void send(const std::string& buf);//关闭连接void shutdown();void setConnectionCallback(const ConnectionCallback& cb){connectionCallback_=cb;}void setMessageCallback(const MessageCallback& cb){messageCallback_=cb;}void setWriteCompleteCallback(const WriteCompleteCallback& cb){writeCompleteCallback_=cb;}void setHighWaterMarkCallback(const HighWaterMarkCallback& cb,size_t highWaterMark){highWaterMarkCallback_=cb; highWaterMark_=highWaterMark;}void setCloseCallback(const CloseCallback& cb){closeCallback_=cb;}//连接建立void connectEstablished();//连接销毁void connectDestroyed();
private:enum StateE{kDisconnected,kConnecting,kConnected,kDisconnecting};void setState(StateE state){state_=state;}void handleRead(Timestamp receiveTime);void handleWrite();void handleClose();void handleError();void sendInLoop(const void* message,size_t len);void shutdownInLoop();EventLoop* loop_;//这里绝对不是baseLoop,因为TcpConnection都是在subloop里面管理的const std::string name_;std::atomic_int state_;bool reading_;//这里和Acceptor类似  Acceptor属于mainLoop  TcpConnection属于subLoopstd::unique_ptr<Socket> socket_;std::unique_ptr<Channel> channel_;const InetAddress localAddr_;const InetAddress peerAddr_;//回调ConnectionCallback connectionCallback_;//有新连接时的回调MessageCallback messageCallback_;//有读写消息时的回调WriteCompleteCallback writeCompleteCallback_;//消息发送完成以后的回调HighWaterMarkCallback highWaterMarkCallback_;//高水位回调CloseCallback closeCallback_;size_t highWaterMark_;//设置水位线高度//数据的缓冲区Buffer inputBuffer_;//接收数据的缓冲区Buffer outputBuffer_;//发送数据的缓冲区
};

2、 TcpConnection.cc

当在上层调用了某一connection的shutdown()方法,设置当前服务器端的状态是disconnecting,然后执行shutdownInLoop,因为shutdownInLoop关闭了socket的write端,poller就给channel通知了关闭事件,就回调TcpConnection::handclose()方法,handclose()方法相当于将channel所有的事件都去掉。

#include "TcpConnection.h"
#include "Logger.h"
#include "Socket.h"
#include "Channel.h"
#include "EventLoop.h"#include <functional>
#include <errno.h>
#include <memory>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <netinet/tcp.h>
#include <sys/socket.h>static EventLoop *CheckLoopNotNull(EventLoop *loop)
{if (loop == nullptr){LOG_FATAL("%s:%s:%d TcpConnection Loop is null!\n", __FILE__, __FUNCTION__, __LINE__);}return loop;
}//已建立连接客户端跟服务器之间的联系
TcpConnection::TcpConnection(EventLoop *loop,const std::string &nameArg,int sockfd,const InetAddress &localAddr,const InetAddress &peerAddr): loop_(CheckLoopNotNull(loop)),name_(nameArg),state_(kConnecting),reading_(true),socket_(new Socket(sockfd)),channel_(new Channel(loop,sockfd)),localAddr_(localAddr),peerAddr_(peerAddr),highWaterMark_(64*1024*1024)//64M
{//下面给channel设置相应的回调函数,poller给channel通知感兴趣的事件发生了,channel会回调相应的操作函数channel_->setReadCallback(std::bind(&TcpConnection::handleRead,this,std::placeholders::_1));channel_->setWriteCallback(std::bind(&TcpConnection::handleWrite,this));channel_->setCloseCallback(std::bind(&TcpConnection::handleClose,this));channel_->setErrorCallback(std::bind(&TcpConnection::handleError,this));LOG_INFO("TcpConnection::ctor[%s] at fd=%d\n",name_.c_str(),sockfd);socket_->setKeepAlive(true);//保活机制}TcpConnection::~TcpConnection()
{LOG_INFO("TcpConnection::dtor[%s] at fd=%d state=%d\n",name_.c_str(),channel_->fd(),(int)state_);
}void TcpConnection::send(const std::string& buf)
{if(state_==kConnected){if(loop_->isInLoopThread()){sendInLoop(buf.c_str(),buf.size());}else{loop_->runInLoop(std::bind(&TcpConnection::sendInLoop,this,buf.c_str(),buf.size()));}}
}/*** 发送数据 应用写的快,而内核发送数据慢,需要把待发送数据写入缓冲区,而且设置了水位回调
*/
void TcpConnection::sendInLoop(const void* data,size_t len)
{ssize_t nwrote=0;size_t remaining=len;//没发送完的数据bool faultError=false;//是否发生错误//之前调用过该connection的shutdown,不能再进行发送了if(state_==kDisconnected){LOG_ERROR("disconnected,give up writing!");return;}//表示channel_第一次开始写数据,而且缓冲区没有待发送数据if(!channel_->isWriting()&&outputBuffer_.readableBytes()==0){nwrote=::write(channel_->fd(),data,len);if(nwrote>=0)//发送成功{remaining=len-nwrote;if(remaining==0&&writeCompleteCallback_){//既然在这里数据全部发送完成,就不用再给channel设置epollout事件了loop_->queueInLoop(std::bind(writeCompleteCallback_,shared_from_this()));}}else //nwrote<0{nwrote=0;//errno==EWOULDBLOCK  由于非阻塞,没有数据时正常的返回if(errno!=EWOULDBLOCK)//真正的错误{LOG_ERROR("TcpConnection::sendInLoop");if(errno==EPIPE||errno==ECONNRESET)// SIGPIPE  RESET 收到连接重置的请求{faultError=true;}}}}//说明当前这一次write,并没有把数据全部发送出去,剩余的数据需要保存到缓冲区当中,然后给channel//注册epollout事件,poller发现tcp的发送缓冲区有空间,会通知相应的sock-channel,调用writeCallback_回调方法//也就是调用TcpConnection::handleWrite方法,把发送缓冲区中的数据全部发送完成if(!faultError&&remaining>0){//目前发送缓冲区剩余的待发送数据的长度size_t oldLen=outputBuffer_.readableBytes();if(oldLen+remaining>=highWaterMark_&&oldLen<highWaterMark_&&highWaterMarkCallback_){loop_->queueInLoop(std::bind(highWaterMarkCallback_,shared_from_this(),oldLen+remaining));//调用水位线回调}outputBuffer_.append((char*)data+nwrote,remaining);//将待发送数据添加到缓冲区中if(!channel_->isWriting()){channel_->enableWriting();//这里一定要注册channel的写事件,否则poller不会给channel通知epollout}}
}// 关闭连接
void TcpConnection::shutdown()
{if(state_==kConnected){setState(kDisconnecting);loop_->runInLoop(std::bind(&TcpConnection::shutdownInLoop,this));}
}void TcpConnection::shutdownInLoop()
{if(!channel_->isWriting())//说明outputBuffer中的数据已经全部发送完成{socket_->shutdownWrite();//关闭写端}
}// 连接建立
void TcpConnection::connectEstablished()
{setState(kConnected);//设置连接成功状态,初始状态为kConnectingchannel_->tie(shared_from_this());//绑定channel,让这个channel记录一下TcpConnection对象存活的状态channel_->enableReading();//同poller注册channel的epollin事件//新连接建立,执行回调connectionCallback_(shared_from_this());
}// 连接销毁
void TcpConnection::connectDestroyed()
{if(state_==kConnected){setState(kDisconnected);channel_->disableAll();//把channel的所有感兴趣的事件,从poller中del掉  相当于epoll_ctlconnectionCallback_(shared_from_this());//断开连接}channel_->remove();//把channel从poller中删除掉
}void TcpConnection::handleRead(Timestamp receiveTime)
{int savedErrno=0;ssize_t n=inputBuffer_.readFd(channel_->fd(),&savedErrno);if(n>0){//已建立连接的用户,有可读事件发生了,调用用户传入的回调操作omMessagemessageCallback_(shared_from_this(),&inputBuffer_,receiveTime);}else if(n==0){handleClose();}else{errno=savedErrno;LOG_ERROR("TcpConnection::handleRead");handleError();}
}
void TcpConnection::handleWrite()
{if(channel_->isWriting()){int savedErrno=0;ssize_t n=outputBuffer_.writeFd(channel_->fd(),&savedErrno);if(n>0){outputBuffer_.retrieve(n);if(outputBuffer_.readableBytes()==0)//发送完成{channel_->disableWriting();//由可写变为不可写if(writeCompleteCallback_){//唤醒loop_对应的thread线程,执行回调loop_->queueInLoop(//loop一定在TcpConnection所对应的线程中std::bind(writeCompleteCallback_,shared_from_this()));}if(state_==kDisconnecting){shutdownInLoop();}}}else{LOG_ERROR("TcpConnection::handleWrite");}}else//执行handlewrite,但channel并不是可写事件{LOG_ERROR("TcpConnection fd=%d is down,no more writing\n",channel_->fd());}
}//poller=>channel::closeCallback=>TcpConnection::handleClose  回调
void TcpConnection::handleClose()
{LOG_INFO("TcpConnection::handleClose fd=%d state=%d \n",channel_->fd(),(int)state_);setState(kDisconnected);channel_->disableAll();//将channel感兴趣的事件从poller上全部删除TcpConnectionPtr connPtr(shared_from_this());connectionCallback_(connPtr);//执行连接关闭的回调closeCallback_(connPtr);//关闭连接的回调   执行的是TcpServer::removeConnection回调方法
}
void TcpConnection::handleError()
{int optval;socklen_t optlen=sizeof optval;int err=0;if(::getsockopt(channel_->fd(),SOL_SOCKET,SO_ERROR,&optval,&optlen)<0){err = errno;}else{err=optval;}LOG_ERROR("TcpConnection::handleError name:%s-SO_ERROR:%d \n",name_.c_str(),err);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/11017.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

泰达克仿钻点水晶饰品包装印刷防滑UV胶特性及应用场景

仿钻点UV滴胶是一种特殊的胶水 常用于模拟钻石的效果 它是一种透明的胶水 具有高光泽度和折射率 可以在物体表面形成类似钻石的亮闪效果 仿钻点UV滴胶通常由紫外线固化胶组成 需要通过紫外线照射来固化和硬化 它具有以下特点&#xff1a; 1. 透明度&#xff1a;仿钻点UV滴胶具有…

BGP第二篇(bgp邻居状态及影响邻居建立的因素)

1、bgp邻居状态 BGP对等体的交互过程中存在6种状态机&#xff1a; 空闲&#xff08;Idle&#xff09; 连接&#xff08;Connect&#xff09; 活跃 &#xff08;Active&#xff09; Open报文已发送&#xff08;OpenSent&#xff09; Open报文已确认&#xff08;OpenConfirm&…

代码-功能-Python-运用bs4技术爬取汽车之家新闻信息

第三方库安装指令&#xff1a; pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple pip install BeautifulSoup4 -i https://pypi.tuna.tsinghua.edu.cn/simple 运行代码&#xff1a; #这个代码并不完整&#xff0c;有很大的问题&#xff0c;但目前不知道怎么…

docker八大架构之单机架构

单机架构 什么是单机架构&#xff1f; 单机架构指的是应用服务和数据库服务公用同一台服务器。如下边两个图所示&#xff0c;当我们进行购物时&#xff0c;所有的物品信息和用户信息都是在同一个服务器下进行运行的&#xff0c;之所以称为单机架构就是因为它所有的操作是在同…

五角钱的程序员 | Kafka 是什么?

本文来源公众号“五角钱的程序员”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;Kafka 是什么&#xff1f; 你是一个程序员&#xff0c;假设你维护了两个服务 A 和 B。B 服务每秒只能处理 100 个消息&#xff0c;但 A 服务却每秒…

数据结构·一篇搞定栈!

好久不见&#xff0c;超级想念 废话不多说&#xff0c;直接看 引言 在数据结构的大家族中&#xff0c;栈&#xff08;Stack&#xff09;是一种非常重要的线性数据结构&#xff0c;它的特点是后进先出&#xff08;LIFO&#xff0c;Last In First Out&#xff09;。栈在程序设…

Echarts旭日图的配置项,强大的层级关系展示图表。

ECharts中的旭日图&#xff08;Sunburst Chart&#xff09;是一种数据可视化图表&#xff0c;用于展示层级关系数据。它通常用于呈现树状结构或层级结构的数据&#xff0c;例如组织结构、文件目录结构、地理区域层级等。 旭日图通过圆形的方式展示数据的层级结构&#xff0c;每…

【Qt 学习笔记】Qt常用控件 | 布局管理器 | 水平布局Horizontal Layout

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 布局管理器 | 水平布局Horizontal Layout 文章编号&…

算法day01

1、[283.移动零](https://leetcode.cn/problems/move-zeroes/) 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 解题思路&#xff1a; 双指针…

IT项目管理-小题计算【太原理工大学】

1.合同总价问题 问承包商的利润是&#xff1f; 实际利润目标利润&#xff08;目标成本-实际成本&#xff09;*卖方分担比例 解&#xff1a;10 000&#xff08;100 000 - 90 000&#xff09;* 0.2 12 000&#xff08;元&#xff09; 实际成本有时也写作最终成本&#xff0c;问承…

Ubuntu 24.04 LTS 安装 touchegg 开启触控板多指手势

文章目录 〇、概述一、安装 touchegg二、安装 gnome-shell 扩展 X11 Gestures三、安装可视化配置工具 touche 〇、概述 之前为了让笔记本支持多指手势&#xff0c;我安装的是 fusuma&#xff0c;安装教程详见 这篇文章 &#xff0c;考虑到 fusuma 安装过程繁琐且不支持可视化配…

Qt自定义控件--提升为

为什么要自定义控件 1&#xff0c;有复合小控件需要组合为一个整体控件时&#xff1b; 2&#xff0c;一个复合控件需要重复使用时&#xff1b; 实现 自定义控件文件 新增三个文件 关联不同组的控件 关联之前的准备工作 1&#xff0c;在主控件选择和子控件所有控件所在控件…

ISIS学习二——与OSPF相比的ISIS报文以及路由计算

目录 一.ISIS支持的网络类型 1.OSPF支持 2.ISIS支持 二.ISIS最优路径的选取 &#xff08;1&#xff09;.ISIS开销值设置 1.全局开销 2.接口开销 3.根据带宽设置开销 &#xff08;2&#xff09;.ISIS的次优路径 三.ISIS报文格式 1.ISIS专用报头——TLV 2.ISIS通用头…

LeetCode-2391. 收集垃圾的最少总时间【数组 字符串 前缀和】

LeetCode-2391. 收集垃圾的最少总时间【数组 字符串 前缀和】 题目描述&#xff1a;解题思路一&#xff1a;处理垃圾和路程单独计算。解题思路二&#xff1a;逆向思维&#xff0c;计算多走的路解题思路三&#xff1a;只记录&#xff0c;当前t需要计算几次 题目描述&#xff1a;…

计算机实战分享3:森林火灾预测分析可视化机器学习预测-完整数据代码-可直接运行

直接看实验数据和结果: 代码: from sklearn import preprocessing import random from sklearn.m

基于LLM的自行车道CAD

LLM&#xff08;大型语言模型&#xff09;是强大的工具。对于许多人来说&#xff0c;用语言表达愿望通常比浏览复杂的 GUI 更简单。 1、系统简介和环境搭建 urb-x.ch&#xff0c;这是一家专门从事自行车道建设的公司。轨道采用模块化构建块进行独特设计&#xff0c;可以通过多…

HCIP的学习(15)

第六章&#xff0c;BGP—边界网关协议 自治系统—AS ​ 定义&#xff1a;由一个单一的机构或组织所管理的一系列IP网络及其设备所构成的集合。 ​ AS的来源&#xff1a; 整个网络规模过大&#xff0c;会导致路由信息收敛速度过慢&#xff0c;设备对相同目标认知不同。AS之间…

全国院校及梯度排序深度解析课(免费下载-帮助更多高考生做出人生重要的选择。)

"全国院校及梯度排序深度解析课"旨在深入探讨全国院校的排名及梯度排序原理。通过系统解析各院校的学术声誉、师资力量、科研水平等因素&#xff0c;帮助学员全面了解院校排名的背后逻辑&#xff0c;为选择合适院校提供理论支持。 课程大小&#xff1a;7G 课程下载…

Java面试之分布式篇

分布式锁的实现方案 &#xff08;1&#xff09;用数据库实现分布式锁比较简单&#xff0c;就是创建一张锁表&#xff0c;数据库对字段作唯一性约束。加锁的时候&#xff0c;在锁表中增加一条记录即可&#xff1b;释放锁的时候删除锁记录就行。如果有并发请求同时提交到数据库&…

css-页面布局-定位大解析-每文一言(世界上,没有人可以支持你一辈子)

&#x1f390;每文一言 世界上,没有人可以支持你一辈子 目录 &#x1f390;每文一言 &#x1f381;css定位 &#x1f9e7;静态定位 position: static &#x1f384;相对定位 position:relative &#x1f380;绝对定位 position:absolute &#x1f383;固定定位 position…