当前位置: 首页 > news >正文

muduo源码剖析之TcpClient客户端类

简介

muduo用TcpClient发起连接,TcpClient有一个Connector连接器,TCPClient使用Conneccor发起连接, 连接建立成功后, 用socket创建TcpConnection来管理连接, 每个TcpClient class只管理一个TcpConnecction,连接建立成功后设置相应的回调函数。很显然,TcpClient用来管理客户端连接,真正连接交给Connector。

主要成员及属性解析

主要接口

回调setters

这些回调函数会在新连接建立时,通过newConnection内部实现方法传递给TcpConnction对象

核心实现:newConnection

在构造时将这个函数作为回调注册给connector_对象
在Connector中的Channel执行本回调后,创建一个新的TcpConnection对象

connect

调用Connector的start接口

stop

调用Connector的stop接口

主要成员

loop

所属workloop

connector

TcpClient所维护的一个连接器

retry_

重连标志

TcpConnection connection_

TcpClient所维护的一个TCP连接对象
关于连接中回调的传递,参考下面的简图:

eb602a687d5a49408a8209145c038271

源码剖析

代码已编写完整注释,

TcpClient.h

// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)
//
// This is a public header file, it must only include public header files.#ifndef MUDUO_NET_TCPCLIENT_H
#define MUDUO_NET_TCPCLIENT_H#include "muduo/base/Mutex.h"
#include "muduo/net/TcpConnection.h"namespace muduo
{
namespace net
{class Connector;
typedef std::shared_ptr<Connector> ConnectorPtr;class TcpClient : noncopyable
{public:// TcpClient(EventLoop* loop);// TcpClient(EventLoop* loop, const string& host, uint16_t port);TcpClient(EventLoop* loop,const InetAddress& serverAddr,const string& nameArg);~TcpClient();  // force out-line dtor, for std::unique_ptr members.void connect();//请求连接void disconnect();//断开连接void stop();//停止连接TcpConnectionPtr connection() const{MutexLockGuard lock(mutex_);return connection_;}EventLoop* getLoop() const { return loop_; }bool retry() const { return retry_; }void enableRetry() { retry_ = true; }const string& name() const{ return name_; }/// Set connection callback./// Not thread safe.void setConnectionCallback(ConnectionCallback cb){ connectionCallback_ = std::move(cb); }/// Set message callback./// Not thread safe.void setMessageCallback(MessageCallback cb){ messageCallback_ = std::move(cb); }/// Set write complete callback./// Not thread safe.void setWriteCompleteCallback(WriteCompleteCallback cb){ writeCompleteCallback_ = std::move(cb); }private:/// Not thread safe, but in loop//新连接建立后的回调函数,将新连接封装为TcpConnection交给TcpClient来管理void newConnection(int sockfd);/// Not thread safe, but in loop释放连接void removeConnection(const TcpConnectionPtr& conn);//所属loopEventLoop* loop_;//Connector,用来处理连接阶段,ConnectorPtr connector_; // avoid revealing Connectorconst string name_;ConnectionCallback connectionCallback_;//连接回调MessageCallback messageCallback_;//消息回调WriteCompleteCallback writeCompleteCallback_;//数据发送完成回调//是否重连bool retry_;   // atomic//是否连接bool connect_; // atomic// always in loop threadint nextConnId_;mutable MutexLock mutex_;//管理连接的TcpConnectionTcpConnectionPtr connection_ GUARDED_BY(mutex_);
};}  // namespace net
}  // namespace muduo#endif  // MUDUO_NET_TCPCLIENT_H

TcpClient.cc

// Copyright 2010, Shuo Chen.  All rights reserved.
// http://code.google.com/p/muduo/
//
// Use of this source code is governed by a BSD-style license
// that can be found in the License file.// Author: Shuo Chen (chenshuo at chenshuo dot com)
//#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 <stdio.h>  // snprintfusing 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(std::bind(&TcpConnection::connectDestroyed, conn));
}void removeConnector(const ConnectorPtr& connector)
{//connector->
}}  // namespace detail
}  // namespace net
}  // namespace muduoTcpClient::TcpClient(EventLoop* loop,const InetAddress& serverAddr,const string& nameArg): loop_(CHECK_NOTNULL(loop)),connector_(new Connector(loop, serverAddr)),name_(nameArg),connectionCallback_(defaultConnectionCallback),messageCallback_(defaultMessageCallback),retry_(false),connect_(true),nextConnId_(1)
{//设置Connector新连接建立的回调函数connector_->setNewConnectionCallback(std::bind(&TcpClient::newConnection, this, _1));// FIXME setConnectFailedCallbackLOG_INFO << "TcpClient::TcpClient[" << name_<< "] - connector " << get_pointer(connector_);
}TcpClient::~TcpClient()
{LOG_INFO << "TcpClient::~TcpClient[" << name_<< "] - connector " << get_pointer(connector_);TcpConnectionPtr conn;bool unique = false;{MutexLockGuard lock(mutex_);//检查所管理对象是否仅由当前 shared_ptr 的实例管理unique = connection_.unique();conn = connection_;}if (conn){assert(loop_ == conn->getLoop());// FIXME: not 100% safe, if we are in different thread//执行断开连接操作CloseCallback cb = std::bind(&detail::removeConnection, loop_, _1);loop_->runInLoop(std::bind(&TcpConnection::setCloseCallback, conn, cb));//如果TcpConnection只有一份,那就强行关闭连接if (unique){conn->forceClose();}}else{connector_->stop();// FIXME: HACKloop_->runAfter(1, std::bind(&detail::removeConnector, connector_));}
}//请求连接服务器
void TcpClient::connect()
{// FIXME: check stateLOG_INFO << "TcpClient::connect[" << name_ << "] - connecting to "<< connector_->serverAddress().toIpPort();connect_ = true;connector_->start();
}//断开连接
void TcpClient::disconnect()
{connect_ = false;{MutexLockGuard lock(mutex_);if (connection_){connection_->shutdown();}}
}void TcpClient::stop()
{connect_ = false;connector_->stop();
}//新连接建立后的回调函数,将新连接封装为TcpConnection交给TcpClient来管理
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;//获取client地址InetAddress localAddr(sockets::getLocalAddr(sockfd));// FIXME poll with zero timeout to double confirm the new connection// FIXME use make_shared if necessary//创建一个TcpConnection,并设置相关回调TcpConnectionPtr conn(new TcpConnection(loop_,connName,sockfd,localAddr,peerAddr));conn->setConnectionCallback(connectionCallback_);conn->setMessageCallback(messageCallback_);conn->setWriteCompleteCallback(writeCompleteCallback_);conn->setCloseCallback(std::bind(&TcpClient::removeConnection, this, _1)); // FIXME: unsafe{MutexLockGuard lock(mutex_);connection_ = conn;}//调用连接建立函数conn->connectEstablished();
}//释放连接
void TcpClient::removeConnection(const TcpConnectionPtr& conn)
{loop_->assertInLoopThread();assert(loop_ == conn->getLoop());{MutexLockGuard lock(mutex_);assert(connection_ == conn);//释放TcpConnectionconnection_.reset();}//在所属loop中执行连接断开释放操作loop_->queueInLoop(std::bind(&TcpConnection::connectDestroyed, conn));//如果设置了重连并且连接标志为true,那就重新连接if (retry_ && connect_){LOG_INFO << "TcpClient::connect[" << name_ << "] - Reconnecting to "<< connector_->serverAddress().toIpPort();connector_->restart();//重新启动}
}

相关文章:

muduo源码剖析之TcpClient客户端类

简介 muduo用TcpClient发起连接&#xff0c;TcpClient有一个Connector连接器&#xff0c;TCPClient使用Conneccor发起连接, 连接建立成功后, 用socket创建TcpConnection来管理连接, 每个TcpClient class只管理一个TcpConnecction&#xff0c;连接建立成功后设置相应的回调函数…...

C语言——switch语句判断星期

#define _CRT_SECURE_NO_WARNINGS 1#include<stdio.h> int main() {int day 0;scanf("请输入1-7之间的整数&#xff1a;%d",&day);switch(day){case 1:printf("星期一\n");break;case 2:printf("星期二\n");break;case 3:printf(&quo…...

栈回溯之CmBacktrace

简介 CmBacktrace &#xff08;Cortex Microcontroller Backtrace&#xff09;是一款针对 ARM Cortex-M 系列 MCU 的错误代码自动追踪、定位&#xff0c;错误原因自动分析的开源库。主要特性如下&#xff1a; 支持的错误包括&#xff1a; 断言&#xff08;assert&#xff09;…...

node插件MongoDB(二)——MongoDB的基本命令

文章目录 前言1. 数据库命令&#xff08;1&#xff09;显示所有数据库&#xff08;2&#xff09;切换指定数据库&#xff08;若没有自动创建&#xff09;&#xff08;3&#xff09;显示当前所在数据库&#xff08;4&#xff09;删除当前数据库 2.集合&#xff08;表名&#xff…...

【Git】推送Github失败:remote: Permission to xxx/*.git denied to xxx

在github上&#xff0c;创建了token&#xff0c;推送代码报没权限 #设置token git remote set-url origin <your.token>github.com/<your.name>/hello-git.git#推送代码 #git push -u origin main remote: Permission to xxx/hello-git.git denied to xxx. fatal:…...

Flink -- 状态与容错

1、Stateful Operations 有状态算子&#xff1a; 有状态计算&#xff0c;使用到前面的数据&#xff0c;常见的有状态的算子&#xff1a;例如sum、reduce&#xff0c;因为它们在计算的时候都是用到了前面的计算的结果 总结来说&#xff0c;有状态计算并不是独立存在的&#xf…...

Linux C语言进阶-D15递归函数和函数指针

递归函数 指一个函数的函数体中直接或间接调用了该函数本身 执行过程分为两个过程&#xff1a; 递推过程&#xff1a;从原问题出发&#xff0c;按递归公式递推从未知到已知&#xff0c;最终达到递推终止条件 回归阶段&#xff1a;按递归终止条件求出结果&#xff0c;逆向逐步…...

LeetCode算法心得——全排列(回溯型排列)

大家好&#xff0c;我是晴天学长&#xff0c;排列型的回溯&#xff0c;需要的小伙伴可以关注支持一下哦&#xff01;后续会继续更新的。&#x1f4aa;&#x1f4aa;&#x1f4aa; 1) .全排列 给定一个不含重复数字的数组 nums &#xff0c;返回其 所有可能的全排列 。你可以 按…...

读取W25Q64的设备ID时输出0xff

发现的问题 读取W25Q64的设备ID时输出0xff 找到的不同解决方法 检查MISO和MOSI是否接对。MISO->DO&#xff0c;MOSI->DI检查程序在初始化spi时是否将SS拉高、SCK拉低如果是硬件spi那么检查SPI的初始化函数中&#xff0c;时钟极性SPI_CPOL误选为SPI_CPOL_Low&#xff0…...

【Docker】Docker 网络

引言 Docker是一个开源的应用容器引擎&#xff0c;它允许开发者将应用及其依赖打包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux机器或Windows机器上&#xff0c;也可以实现虚拟化。Docker的主要优势之一是其网络功能&#xff0c;而网络功能的核心就是网络驱动…...

Flutter学习:使用CustomPaint绘制路径

Flutter学习&#xff1a;认识CustomPaint组件和Paint对象 Flutter学习&#xff1a;使用CustomPaint绘制路径 Flutter学习&#xff1a;使用CustomPaint绘制图形 Flutter学习&#xff1a;使用CustomPaint绘制文字 Flutter学习&#xff1a;使用CustomPaint绘制图片 drawPath 绘制路…...

软件模拟SPI协议的理解和使用编写W25Q64

SPI软件模拟的时序 SPI协议中&#xff0c;NSS、SCK、MOSI由主机产生&#xff0c;MISO由从机产生&#xff0c;在SCK每个时钟周期MOSI、MISO传输一位数据&#xff0c;数据的输入输出是同时进行的&#xff0c;所以读写数据也可以视作交换数据。所以读写时对数据位的控制都是用同一…...

SQLI手动注入和python sqlmap代码注入

sql教程&#xff1a; https://www.w3school.com.cn/sql/index.asp数据库&#xff1a; mysql oracle mssql常用方法 system_user() 系统用户名 user() 用户名 current_user() 当前用户名 session_user() 连接数据库的用户名 d…...

MemcachedRedis构建缓存服务器 (数据持久化,主从同步,哨兵模式)

Memcached/redis是高性能的分布式内存缓存服务器,通过缓存数据库查询结果&#xff0c;减少数据库访问次数&#xff0c;以提高动态Web等应用的速度、 提高可扩展性。降低数据库读的压力 Nsql的优点&#xff1a;高可扩展性&#xff0c;分布式计算&#xff0c;低成本&#xff0c;…...

Python语法基础(变量 注释 数据类型 输入与输出 运算符 缩进)

目录 变量变量命名规则变量的类型变量的创建变量的作用域 注释的方法数据类型对象和引用的概念Number(数字)数据转换 输入与输出输入函数输出函数输出函数的end参数输出格式多行语句 运算符算术运算符赋值运算符三目运算符运算符的优先级 缩进缩进格式注意事项层级嵌套 变量 标…...

linux espeak语音tts;pyttsx3 ubuntu使用

整体使用espeak声音很机械不太自然 1、linux espeak语音tts 安装&#xff1a; sudo apt install espeak使用&#xff1a; #中文男声 espeak -v zh 你好 #中文女声 espeak -v zhf3 你好 #粤语男声 espeak -v zhy 你好注意&#xff1a;espeak -v zh 你好 &#xff08;Full d…...

小白该如何学习Linux操作系统?

&#x1f482; 个人网站:【工具大全】【游戏大全】【神级源码资源网】&#x1f91f; 前端学习课程&#xff1a;&#x1f449;【28个案例趣学前端】【400个JS面试题】&#x1f485; 寻找学习交流、摸鱼划水的小伙伴&#xff0c;请点击【摸鱼学习交流群】 Linux作为一种开源操作系…...

2023双十一:实体门店闯入,第二战场全面开战

“闺女&#xff0c;吃饺子了吗&#xff1f;”11月8日&#xff0c;立冬&#xff0c;忙碌一天的陈曦回家路上接到母亲电话&#xff0c;才想起来家里冷冻水饺没了&#xff0c;又不想再去超市&#xff0c;直接打开美团买菜买了两袋&#xff0c;回家就煮了吃。当然&#xff0c;最终她…...

操作系统·处理机调度死锁

3.1 处理机调度概述 3.1.1 处理机调度概述 高级调度 (High level Scheduling)决定把外存上哪些作业调入内存、创建进程、分配资源。高级调度又称作业调度、长程调度或宏观调度。只在批处理系统中有高级调度。 中级调度 (Middle level Scheduling)完成进程的部分或全部在内、…...

SQL第四次上机实验

1.查询借阅了计算机类或者文学类图书的读者的借书证号 USE TSGL GO SELECT DISTINCT Reader.Lno FROM Book,Lend,Reader WHERE Book.ISBNLend.ISBN AND Lend.LnoReader.Lno AND Class 计算机类 OR Class 文学类2.查询同时借阅了计算机类和文学类图书的读者的借书证号 USE T…...

iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘

美国西海岸的夏天&#xff0c;再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至&#xff0c;这不仅是开发者的盛宴&#xff0c;更是全球数亿苹果用户翘首以盼的科技春晚。今年&#xff0c;苹果依旧为我们带来了全家桶式的系统更新&#xff0c;包括 iOS 26、iPadOS 26…...

JavaScript 中的 ES|QL:利用 Apache Arrow 工具

作者&#xff1a;来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗&#xff1f;了解下一期 Elasticsearch Engineer 培训的时间吧&#xff01; Elasticsearch 拥有众多新功能&#xff0c;助你为自己…...

UDP(Echoserver)

网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法&#xff1a;netstat [选项] 功能&#xff1a;查看网络状态 常用选项&#xff1a; n 拒绝显示别名&#…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

Mac下Android Studio扫描根目录卡死问题记录

环境信息 操作系统: macOS 15.5 (Apple M2芯片)Android Studio版本: Meerkat Feature Drop | 2024.3.2 Patch 1 (Build #AI-243.26053.27.2432.13536105, 2025年5月22日构建) 问题现象 在项目开发过程中&#xff0c;提示一个依赖外部头文件的cpp源文件需要同步&#xff0c;点…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

【分享】推荐一些办公小工具

1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由&#xff1a;大部分的转换软件需要收费&#xff0c;要么功能不齐全&#xff0c;而开会员又用不了几次浪费钱&#xff0c;借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...

【LeetCode】3309. 连接二进制表示可形成的最大数值(递归|回溯|位运算)

LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 题目描述解题思路Java代码 题目描述 题目链接&#xff1a;LeetCode 3309. 连接二进制表示可形成的最大数值&#xff08;中等&#xff09; 给你一个长度为 3 的整数数组 nums。 现以某种顺序 连接…...