(十五)TcpClient
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相关推荐
- 【零基础学Java】—Socket类(五十五)
[零基础学Java]-Socket类(五十五) Socket类:该类实现客户端套接字,套接字是指两台设备之间通讯的端点. 在Java中,提供了两个类用于实现TCP通信程序 客户端:java.net.S ...
- 2021年大数据HBase(十五):HBase的Bulk Load批量加载操作
全网最详细的大数据HBase文章系列,强烈建议收藏加关注! 新文章都已经列出历史文章目录,帮助大家回顾前面的知识重点. 目录 系列历史文章 HBase的Bulk Load批量加载操作 一.Bulk L ...
- 2021年大数据Hadoop(二十五):YARN通俗介绍和基本架构
全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 YARN通俗介绍和基本架构 Yarn通俗介绍 Yarn基本 ...
- 2021年大数据Hadoop(十五):Hadoop的联邦机制 Federation
全网最详细的Hadoop文章系列,强烈建议收藏加关注! 后面更新文章都会列出历史文章目录,帮助大家回顾知识重点. 目录 本系列历史文章 前言 Hadoop的联邦机制 Federation 背景概述 F ...
- 十五天精通WCF——第六天 你必须要了解的3种通信模式
十五天精通WCF--第六天 你必须要了解的3种通信模式 原文:十五天精通WCF--第六天 你必须要了解的3种通信模式 wcf已经说到第六天了,居然还没有说到这玩意有几种通信模式,惭愧惭愧,不过很简单啦 ...
- opengl正方形绕点旋转_一题十五种解法够不够? 旋转,构造,四点共圆乐不停...
平移,旋转,轴对称是我们初中学习的"几何三大变换".在我们初中阶段学习的几何知识中占据着核心的地位,特别是旋转,那更是核心中的核心(河南中考22题年年考). 如何更好的理解旋转,如 ...
- NeHe OpenGL第三十五课:播放AVI
NeHe OpenGL第三十五课:播放AVI 在OpenGL中播放AVI: 在OpenGL中如何播放AVI呢?利用Windows的API把每一帧作为纹理绑定到OpenGL中,虽然很慢,但它的效果不错. ...
- 转:中国互联网十五年的22个创新模式
中国互联网十五年的22个创新模式 今天,看网上有人推荐<沸腾十五年>,讲中国互联网从发源到现今. 有人有如此梳理,自己本来也想梳理一下中国互联网这么多年,到底是哪些公司出来了,为什 ...
- 15crmo焊接后多长时间探伤_15CrMo十五铬钼属于合金钢?、下面来解释一下
15CrMo十五铬钼属于合金钢,主要用于石油.石化.高压锅炉等,专门用途的无缝管有锅炉用无缝管.地质用无缝钢管及石油用无缝管等多种. 一.15CrMo化学成分: C:0.12-0.18 Mn:0. ...
- 微信小程序把玩(三十五)Video API
原文:微信小程序把玩(三十五)Video API 电脑端不能测试拍摄功能只能测试选择视频功能,好像只支持mp4格式,值得注意的是成功之后返回的临时文件路径是个列表tempFilePaths而不是tem ...
最新文章
- Zookeeper集群部署和使用
- 关于骨骼动画及微软示例Skinned Mesh的解析
- 大型网站架构的发展演变过程
- 【无码专区6】球与盒子(数学线性筛)
- 前端学习(3251):样式的模块化
- CCF201509-2 日期计算(100分)
- android dropbox切换账户,android – 如何获取我的APP_KEY和SECRET_KEY的Dropbox同步?
- php集成开发环境xampp的搭建
- 网易云通信 java 登录,网易云IM(即时通讯) 集成指南(Android)
- ## 作为多目标优化的多任务学习:寻找帕累托最优解+组合在线学习:实时反馈玩转组合优化-微软研究院+用于组合优化的强化学习:学习策略解决复杂的优化问题
- Word 插入参考文献 通过尾注插入并更改尾注罗马数字为阿拉伯数字
- 网络面试一百问<待整理>
- 引入的噪声程度:曝光时间,模拟增益,数字增益的不同
- 计算机硬件系统的主要性能指标
- python安装第三方库超时
- MongoDB中balancer操作
- Uber数据泄露事件本可以使用区块链…
- 一个游戏创业者如何跳出模式
- 怎么批量把图片转文字?教你几招轻松完成
- 5.Numpy数组中数据的抽取
热门文章
- 微信表情包储服务器,微信表情包不用收藏,只需打开这个设置,再也不担心斗图了...
- MAC wps中选中的页面和缩放打印
- PS给人物添加阴影和高光
- ubuntu WeChat 网易云音乐 Mac OS主题 wps 截图链接版
- ies4linux 本地安装,Linux下离线安装ies4linux
- 字典(数字大小写转换器)
- 视频下载工具you-get(哔哩哔哩巨好用)
- 无法定位程序输入点K32Get Module File Name Ex于动态链接库KERNEL32.dll上 的错误解析
- English音标(全)与单词家园
- radon变换的原理-通过直线方程式的计算来检测出直线