TcpClient 和 TcpServer 实现相似,都有newConnection 建立连接,removeConnection 断开连接,但是TcpClient 只管理一个TcpConnection 的生命周期,即主动连接时(newConnection)产生的;

class TcpClient {// ...private:void newConnection(int sockfd);void removeConnection(const TcpConnectionPtr &conn);EventLoop *_loop;ConnectorPtr _connector;ConnectionCallback _connectionCallback;MessageCallback _messageCallback;WriteCompleteCallback _writeCompleteCallback;bool _retry;bool _connect;int _nextConnId;mutable MutexLock _mutex;TcpConnectionPtr _connection;
};

TcpClient 在Connector 基础上提供了一层封装,并在构造中设置好Connector newConnection;

TcpClient::TcpClient(EventLoop *loop, const InetAddress &serverAddr): _loop(CHECK_NOTNULL(loop)), _connector(new Connector(loop, serverAddr)),_retry(false), _connect(false), _nextConnId(1) {_connector->setNewConnectionCallback(std::bind(&TcpClient::newConnection, this, _1));// FIXME setConnectFailedCallbackLOG_INFO << "TcpClient::TcpClient[" << this << "] - connector "<< _connector.get();
}

值得注意的是:
_nextConnId 表示下一次连接编号(触发newConection 会导致其增加)
_mutex 保障线程间接触TcpClient::TcpConnectionPtr _connection 的线程安全

_mutex 在TcpClient.cc 出现过四次

void TcpClient::removeConnection(const TcpConnectionPtr &conn) {_loop->assertInLoopThread();assert(_loop == conn->getLoop());{MutexLockGuard lock(_mutex);assert(_connection == conn);_connection.reset();}// ...
}
TcpClient::~TcpClient() {// ...TcpConnectionPtr conn;{MutexLockGuard lock(_mutex);conn = _connection;}// ...
}
void TcpClient::disconnect() {_connect = false;{MutexLockGuard lock(_mutex);if (_connector) {_connection->shutdown();}}
}
void TcpClient::newConnection(int sockfd) {_loop->assertInLoopThread();// ...{MutexLockGuard lock(_mutex);_connection = conn;}conn->connectEstablished();
}

removeConnection 和 newConnection 保证只在IO 线程触发,而TcpClient 对外接口disconnect 无此需求;

跨线程调用TcpClient disconnect,TcpConnectionPtr _connection 此时不可被占用(假如TcpConnection 还在占线,禁止连接会导致未预期的结果),因此_mutex 在_connection 操作时需要先lock 一下;(client 只有一个connector,在新连接和旧连接的处理选择中一定要保证生命周期正常结束)

有趣的是类似TcpClient 的TcpServer 类中并没有TcpConnectionPtr,在其newConnection 中TcpConnectionPtr 连接即用即产生,由Map 保存并延长生命周期(server 1:n,client 1:1),因此在TcpServer 中每个连接都是新连接,在操作时不会受到跨线程干扰;

析构中的处理也要保证连接正常结束,在muduo 源码更直观:

TcpClient::~TcpClient()
{LOG_INFO << "TcpClient::~TcpClient[" << name_<< "] - connector " << get_pointer(connector_);TcpConnectionPtr conn;bool unique = false;{MutexLockGuard lock(mutex_);unique = connection_.unique();conn = connection_;}//....
}

conn 连接是否为unique(还有处理没有结束),会决定Client 析构中关不关闭连接;

if (conn){assert(loop_ == conn->getLoop());// FIXME: not 100% safe, if we are in different threadCloseCallback cb = std::bind(&detail::removeConnection, loop_, _1);loop_->runInLoop(std::bind(&TcpConnection::setCloseCallback, conn, cb));if (unique){conn->forceClose();}}else{connector_->stop();// FIXME: HACKloop_->runAfter(1, std::bind(&detail::removeConnector, connector_));}

else 分支处理的是没有触发newConnection,TcpClient 安稳关闭,而这儿runAfter 好有灵性…

因为需要关闭connector 关系到 _timerId(retry 实现依据_timerId),而stop 本质就是将cancel _timerId 放到Loop 中等待IO 线程中注销(不一定是即时的),在此过程中TcpClient 会析构,_connector 作为shared_ptr 引用会减少,runAfter 相当于无条件延长_connector 生命周期1s,相信在1s 内其IO 线程的Loop 会处理完 cancel 事件… 怪不得有FIXME: Hack

这儿安全处理应该添加判断retry 分支,再在有retry 设定的分支中等待Loop 完成IO 注销;
关键怎么等待?…
如果就是在IO 线程cancel 则没有问题,Loop 会立刻处理,但如不在,runInLoop 变成 queueInLoop cancel 则不会即时处理;
不知道,

(十五)TcpClient相关推荐

  1. 【零基础学Java】—Socket类(五十五)

    [零基础学Java]-Socket类(五十五) Socket类:该类实现客户端套接字,套接字是指两台设备之间通讯的端点. 在Java中,提供了两个类用于实现TCP通信程序 客户端:java.net.S ...

  2. 2021年大数据HBase(十五):HBase的Bulk Load批量加载操作

    全网最详细的大数据HBase文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 HBase的Bulk Load批量加载操作 一.Bulk L ...

  3. 2021年大数据Hadoop(二十五):YARN通俗介绍和基本架构

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 YARN通俗介绍和基本架构 Yarn通俗介绍 Yarn基本 ...

  4. 2021年大数据Hadoop(十五):Hadoop的联邦机制 Federation

    全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 Hadoop的联邦机制 Federation 背景概述 F ...

  5. 十五天精通WCF——第六天 你必须要了解的3种通信模式

    十五天精通WCF--第六天 你必须要了解的3种通信模式 原文:十五天精通WCF--第六天 你必须要了解的3种通信模式 wcf已经说到第六天了,居然还没有说到这玩意有几种通信模式,惭愧惭愧,不过很简单啦 ...

  6. opengl正方形绕点旋转_一题十五种解法够不够? 旋转,构造,四点共圆乐不停...

    平移,旋转,轴对称是我们初中学习的"几何三大变换".在我们初中阶段学习的几何知识中占据着核心的地位,特别是旋转,那更是核心中的核心(河南中考22题年年考). 如何更好的理解旋转,如 ...

  7. NeHe OpenGL第三十五课:播放AVI

    NeHe OpenGL第三十五课:播放AVI 在OpenGL中播放AVI: 在OpenGL中如何播放AVI呢?利用Windows的API把每一帧作为纹理绑定到OpenGL中,虽然很慢,但它的效果不错. ...

  8. 转:中国互联网十五年的22个创新模式

    中国互联网十五年的22个创新模式     今天,看网上有人推荐<沸腾十五年>,讲中国互联网从发源到现今. 有人有如此梳理,自己本来也想梳理一下中国互联网这么多年,到底是哪些公司出来了,为什 ...

  9. 15crmo焊接后多长时间探伤_15CrMo十五铬钼属于合金钢?、下面来解释一下

    15CrMo十五铬钼属于合金钢​,主要用于石油.石化.高压锅炉等,专门用途的无缝管有锅炉用无缝管.地质用无缝钢管及石油用无缝管等多种.​ 一.15CrMo化学成分: C:0.12-0.18 Mn:0. ...

  10. 微信小程序把玩(三十五)Video API

    原文:微信小程序把玩(三十五)Video API 电脑端不能测试拍摄功能只能测试选择视频功能,好像只支持mp4格式,值得注意的是成功之后返回的临时文件路径是个列表tempFilePaths而不是tem ...

最新文章

  1. Zookeeper集群部署和使用
  2. 关于骨骼动画及微软示例Skinned Mesh的解析
  3. 大型网站架构的发展演变过程
  4. 【无码专区6】球与盒子(数学线性筛)
  5. 前端学习(3251):样式的模块化
  6. CCF201509-2 日期计算(100分)
  7. android dropbox切换账户,android – 如何获取我的APP_KEY和SECRET_KEY的Dropbox同步?
  8. php集成开发环境xampp的搭建
  9. 网易云通信 java 登录,网易云IM(即时通讯) 集成指南(Android)
  10. ## 作为多目标优化的多任务学习:寻找帕累托最优解+组合在线学习:实时反馈玩转组合优化-微软研究院+用于组合优化的强化学习:学习策略解决复杂的优化问题
  11. Word 插入参考文献 通过尾注插入并更改尾注罗马数字为阿拉伯数字
  12. 网络面试一百问<待整理>
  13. 引入的噪声程度:曝光时间,模拟增益,数字增益的不同
  14. 计算机硬件系统的主要性能指标
  15. python安装第三方库超时
  16. MongoDB中balancer操作
  17. Uber数据泄露事件本可以使用区块链…
  18. 一个游戏创业者如何跳出模式
  19. 怎么批量把图片转文字?教你几招轻松完成
  20. 5.Numpy数组中数据的抽取

热门文章

  1. 微信表情包储服务器,微信表情包不用收藏,只需打开这个设置,再也不担心斗图了...
  2. MAC wps中选中的页面和缩放打印
  3. PS给人物添加阴影和高光
  4. ubuntu WeChat 网易云音乐 Mac OS主题 wps 截图链接版
  5. ies4linux 本地安装,Linux下离线安装ies4linux
  6. 字典(数字大小写转换器)
  7. 视频下载工具you-get(哔哩哔哩巨好用)
  8. 无法定位程序输入点K32Get Module File Name Ex于动态链接库KERNEL32.dll上 的错误解析
  9. English音标(全)与单词家园
  10. radon变换的原理-通过直线方程式的计算来检测出直线