【Qt学习】02:信号和槽机制
信号和槽机制
OVERVIEW
- 信号和槽机制
- 一、系统自带信号与槽
- 二、自定义信号与槽
- 1.基本使用
- student.cpp
- teacher.cpp
- widget.cpp
- main.cpp
- 2.信号与槽重载
- student.cpp
- teacher.cpp
- widget.cpp
- main.cpp
- 3.信号连接信号
- 4.Lambda表达式
- 5.信号与槽总结
信号槽机制是 Qt 框架引以为豪的机制之一。
所谓信号槽实际就是观察者模式,将要处理的信号和自己的一个函数/槽slot绑定来处理信号,当某个事件发生之后检测对象就会发出信号(无目的的广播),如果有其他对象对这个信号感兴趣就会使用connect函数进行连接。
即当信号发出时,被连接的槽函数会自动被回调。类似观察者模式:当发生了感兴趣的事件,某个操作就会被自动触发。
一、系统自带信号与槽
信号槽的优点:松散耦合,信号发送方和接收方本身是没有关联的,通过connect连接将两端耦合在一起
QPushButton * quitBtn = new QPushButton("quit",this);//创建关闭按钮
connect(quitBtn, &QPushButton::clicked, this, &QWidget::close);//信号槽使用方式
函数connect(sender, signal, receiver, slot);参数解释:
- sender:发出信号的对象
- signal:发送对象发出的信号
- receiver:接收信号的对象
- slot:接收对象在接收到信号之后所需要调用的函数(槽函数)
利用帮助文档了查找系统自带的信号和槽,在帮助文档中如按钮的点击信号输入QPushButton,首先我们可以在Contents中寻找关键字 signals信号的意思,但是我们发现并没有找到,这时候我们应该想到也许这个信号的被父类继承下来的,因此我们去他的父类QAbstractButton中就可以找到该关键字,点击signals索引到系统自带的信号有如下几个。
这里的clicked就是我们要找到,槽函数的寻找方式和信号一样,只不过他的关键字是slot。
二、自定义信号与槽
使用connect可使用系统提供的信号和槽,
但Qt的信号槽机制并不仅仅是使用系统提供那部分,其还允许开发者设计自己的信号和槽,
1.基本使用
student.cpp
#ifndef STUDENT_H
#define STUDENT_H#include <QObject>class Student : public QObject {Q_OBJECT
public:explicit Student(QObject *parent = nullptr);
signals:public slots://槽函数slot 返回值是void 需要声明需要实现 可以有参数(发生重载)void treat();
};#endif // STUDENT_H
#include "student.h"
#include <QDebug>Student::Student(QObject *parent) : QObject(parent) { }void Student::treat() {qDebug() << "debug: receive signal. student treats teacher.";
}
teacher.cpp
#ifndef TEACHER_H
#define TEACHER_H#include <QObject>class Teacher : public QObject {Q_OBJECT
public:explicit Teacher(QObject *parent = nullptr);
signals://信号signal 返回值是void 只需要声明不需要实现 可以有参数(发生重载)void hungry();
public slots:};#endif // TEACHER_H
#include "teacher.h"Teacher::Teacher(QObject *parent) : QObject(parent) { }
widget.cpp
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "teacher.h"
#include "student.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECT
public:Widget(QWidget *parent = nullptr);~Widget();void classIsOver();
private:Ui::Widget *ui;Teacher *tch;Student *stu;
};#endif // WIDGET_H
#include <QPushButton>
#include <QDebug>
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//1.第一次绑定 使用系统自带信号与槽函数QPushButton *mybtn = new QPushButton("myBtn", this);mybtn->resize(100, 30);connect(mybtn, &QPushButton::clicked, this, &Widget::classIsOver);//按钮触发classIsOver函数//2.第二次绑定 使用自定义信号与槽函数tch = new Teacher(this);//初始化老师对象stu = new Student(this);//初始化学生对象connect(tch, &Teacher::hungry, stu, &Student::treat);//老师饿了时学生主动请客的connect连接
}Widget::~Widget() {delete ui;
}void Widget::classIsOver() {qDebug() << "debug: btn is pushed and Widget::classIsOver was called. emitting signal...";emit tch->hungry();//函数被调用 则触发发送老师饿了的信号
}
main.cpp
#include <QApplication>
#include "widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

2.信号与槽重载
student.cpp
#ifndef STUDENT_H
#define STUDENT_H#include <QObject>class Student : public QObject {Q_OBJECT
public:explicit Student(QObject *parent = nullptr);
signals:public slots://槽函数slot 返回值是void 需要声明需要实现 可以有参数(发生重载)void treat();void treat(QString food);
};#endif // STUDENT_H
#include "student.h"
#include <QDebug>Student::Student(QObject *parent) : QObject(parent) { }void Student::treat() {qDebug() << "debug: receive signal. student treats teacher.";
}void Student::treat(QString food) {qDebug() << "debug: receive signal. student treats teacher with " << food.toUtf8().data();
}
teacher.cpp
#ifndef TEACHER_H
#define TEACHER_H#include <QObject>class Teacher : public QObject {Q_OBJECT
public:explicit Teacher(QObject *parent = nullptr);
signals://信号signal 返回值是void 只需要声明不需要实现 可以有参数(发生重载)void hungry();void hungry(QString food);
public slots:};#endif // TEACHER_H
#include "teacher.h"Teacher::Teacher(QObject *parent) : QObject(parent) { }
widget.cpp
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include "teacher.h"
#include "student.h"QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECT
public:Widget(QWidget *parent = nullptr);~Widget();void classIsOver1();void classIsOver2();
private:Ui::Widget *ui;Teacher *tch;Student *stu;
};#endif // WIDGET_H
#include <QPushButton>
#include <QDebug>
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//1.第一次绑定 使用系统自带信号与槽函数QPushButton *mybtn1 = new QPushButton("myBtn1", this);mybtn1->resize(100, 30);connect(mybtn1, &QPushButton::clicked, this, &Widget::classIsOver1);//按钮触发classIsOver函数QPushButton *mybtn2 = new QPushButton("myBtn2", this);mybtn2->move(100, 0);mybtn2->resize(100, 30);connect(mybtn2, &QPushButton::clicked, this, &Widget::classIsOver2);//按钮触发classIsOver函数tch = new Teacher(this);//初始化老师对象stu = new Student(this);//初始化学生对象//2.第二次绑定 使用自定义信号与槽函数void(Teacher::*tchsignal_)() = &Teacher::hungry;void(Student::*stusignal_)() = &Student::treat;connect(tch, tchsignal_, stu, stusignal_);//老师饿了时学生主动请客的connect连接//3.第三次绑定 使用自定义信号与槽函数//定义函数指针 用于识别重载的函数地址void(Teacher::*tchsignal)(QString) = &Teacher::hungry;void(Student::*stusignal)(QString) = &Student::treat;connect(tch, tchsignal, stu, stusignal);
}Widget::~Widget() {delete ui;
}void Widget::classIsOver1() {qDebug() << "debug: btn1 is pushed and Widget::classIsOver1 was called. emitting signal...";emit tch->hungry();//函数被调用 则触发发送老师饿了的信号
}void Widget::classIsOver2() {qDebug() << "debug: btn2 is pushed and Widget::classIsOver2 was called. emitting signal...";emit tch->hungry("apple pie");
}
main.cpp
#include <QApplication>
#include "widget.h"int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

3.信号连接信号
之前的使用中都是利用槽函数实现的,点击btn按钮触发函数调用,函数调用后emit发出信号再触发slot槽函数,从而实现连续的效果。
也可以使用另一种方式信号触发信号完成,利用点击btn按钮的信号去触发另一个信号,
主要对widget.cpp中的内容进行修改,修改后如下:
#include <QPushButton>
#include <QDebug>
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);//1.第一次绑定 使用系统自带信号与槽函数QPushButton *mybtn1 = new QPushButton("myBtn1", this);mybtn1->resize(100, 30);//connect(mybtn1, &QPushButton::clicked, this, &Widget::classIsOver1);//按钮触发classIsOver函数QPushButton *mybtn2 = new QPushButton("myBtn2", this);mybtn2->move(100, 0);mybtn2->resize(100, 30);//connect(mybtn2, &QPushButton::clicked, this, &Widget::classIsOver2);//按钮触发classIsOver函数tch = new Teacher(this);//初始化老师对象stu = new Student(this);//初始化学生对象//2.第二次绑定 使用自定义信号与槽函数void(Teacher::*tchsignal_)() = &Teacher::hungry;void(Student::*stusignal_)() = &Student::treat;connect(tch, tchsignal_, stu, stusignal_);//老师饿了时学生主动请客的connect连接connect(mybtn1, &QPushButton::clicked, tch, tchsignal_);//信号连接信号//3.第三次绑定 使用自定义信号与槽函数//定义函数指针 用于识别重载的函数地址void(Teacher::*tchsignal)(QString) = &Teacher::hungry;void(Student::*stusignal)(QString) = &Student::treat;connect(tch, tchsignal, stu, stusignal);//connect(mybtn2, &QPushButton::clicked, tch, tchsignal);//信号连接信号connect(mybtn2, &QPushButton::clicked, this, [=](){emit tch->hungry("apple pie");});
}Widget::~Widget() {delete ui;
}void Widget::classIsOver1() {qDebug() << "debug: btn1 is pushed and Widget::classIsOver1 was called. emitting signal...";emit tch->hungry();//函数被调用 则触发发送老师饿了的信号
}void Widget::classIsOver2() {qDebug() << "debug: btn2 is pushed and Widget::classIsOver2 was called. emitting signal...";emit tch->hungry("apple pie");
}

btn触发信号连接信号,跳过了classIsOver函数的中间调用过程,直接实现了最终结果的输出。
4.Lambda表达式
C++11中的Lambda表达式用于定义并创建匿名的函数对象以简化编程工作,Lambda表达式的基本构成:
[capture](parameters)mutable->returnType {statement
}
-
函数对象参数;
[],标识一个Lambda的开始,这部分必须存在不能省略。函数对象参数是传递给编译器自动生成的函数对象类的构造函数的。函数对象参数只能使用那些到定义Lambda为止时Lambda所在作用范围内可见的局部变量(包括Lambda所在类的this)。函数对象参数有以下形式:- void,没有使用任何函数对象参数。
- =,函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是值传递方式(相当于编译器自动为我们按值传递了所有局部变量)
- &,函数体内可以使用Lambda所在作用范围内所有可见的局部变量(包括Lambda所在类的this),并且是引用传递方式(相当于编译器自动为我们按引用传递了所有局部变量)
- this,函数体内可以使用Lambda所在类中的成员变量
- a,将a按值进行传递。按值进行传递时,函数体内不能修改传递进来的a的拷贝,因为默认情况下函数是const的。要修改传递进来的a的拷贝,可以添加mutable修饰符
- &a,将a按引用进行传递。
- a, &b,将a按值进行传递,b按引用进行传递。
- =,&a, &b,除a和b按引用进行传递外,其他参数都按值进行传递。
- &, a, b,除a和b按值进行传递外,其他参数都按引用进行传递。
-
操作符重载函数参数;标识重载的
()操作符的参数,没有参数时这部分可以省略。参数可以通过按值(如:(a,b))和按引用(如:(&a,&b))两种方式进行传递 -
可修改标示符;
mutable声明,这部分可以省略。按值传递函数对象参数时,加上mutable修饰符后,可以修改按值传递进来的拷贝(注意是能修改拷贝,而不是值本身)QPushButton * myBtn = new QPushButton (this); QPushButton * myBtn2 = new QPushButton (this); myBtn2->move(100,100); int m = 10;connect(myBtn,&QPushButton::clicked,this,[m] ()mutable { m = 100 + 10; qDebug() << m; }); connect(myBtn2,&QPushButton::clicked,this,[=] () { qDebug() << m; }); qDebug() << m; -
函数返回值;
->返回值类型,标识函数返回值的类型,当返回值为void,或者函数体中只有一处return的地方(此时编译器可以自动推断出返回值类型)时,这部分可以省略。 -
是函数体;
{},标识函数的实现这部分不能省略,但函数体可以为空。
利用Lambda表达式简化信号与槽的使用机制:利用lambda表达式实现点击按钮,关闭窗口:
QPushButton *btn = new QPushButton;
btn->setText("quit");
connect(btn, &QPushButton::clicked, this, [=](){this->close();
});
5.信号与槽总结

自定义信号槽需要注意的事项:
- 发送者和接收者都需要是QObject的子类(槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
- 自定义信号signal返回值是 void,只需要声明不需要实现,可以有参数(发生重载)
- 槽函数是普通的成员函数,需要声明也需要实现,会受到 public、private、protected 的影响(早期必须写到public slots作用域下)
- 任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数
信号与槽的连接:connect函数
- 一个信号可以和多个槽函数相连:如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的
- 多个信号可以连接到一个槽:只要任意一个信号发出,这个槽就会被调用
- 一个信号可以连接到另外的一个信号:当第一个信号发出时第二个信号被发出,除此之外这种信号-信号的形式和信号-槽的形式没有什么区别。
- 信号槽要求信号和槽的参数类型对应(参数的个数信号可以多于槽函数,反之报错)
- 若信号和槽的参数不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。这是因为可以在槽函数中选择忽略信号传来的数据(也就是槽函数的参数比信号的少)。
- 槽可以被取消链接:这种情况并不经常出现,因为当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽
- 使用Lambda 表达式:在使用 Qt 5 的时候,能够支持 Qt 5 的编译器都是支持 Lambda 表达式的,在连接信号和槽的时候,槽函数可以使用Lambda表达式的方式进行处理。
QT4版本的信号槽写法:Qt5在语法上完全兼容Qt4。
connect(tch, SIGNAL(hungry(QString)), stu, SLOT(treat(QString)));
这里使用了SIGNAL和SLOT这两个宏,将两个函数名转换成了字符串。注意到connect函数的signal和slot都是接受字符串,一旦出现连接不成功的情况,Qt4是没有编译错误的(因为一切都是字符串编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不稳定性。
相关文章:
【Qt学习】02:信号和槽机制
信号和槽机制 OVERVIEW 信号和槽机制一、系统自带信号与槽二、自定义信号与槽1.基本使用student.cppteacher.cppwidget.cppmain.cpp 2.信号与槽重载student.cppteacher.cppwidget.cppmain.cpp 3.信号连接信号4.Lambda表达式5.信号与槽总结 信号槽机制是 Qt 框架引以为豪的机制之…...
软件工程(十三) 设计模式之结构型设计模式(一)
前面我们记录了创建型设计模式,知道了通过各种模式去创建和管理我们的对象。但是除了对象的创建,我们还有一些结构型的模式。 1、适配器模式(Adapter) 简要说明 将一个类的接口转换为用户希望得到的另一个接口。它使原本不相同的接口得以协同工作。 速记关键字 转换接…...
Node与Express后端架构:高性能的Web应用服务
在现代Web应用开发中,后端架构的性能和可扩展性至关重要。Node.js作为一个基于事件驱动、非阻塞I/O的平台,以及Express作为一个流行的Node.js框架,共同构建了高性能的Web应用服务。 在本文中,我们将深入探讨Node与Express后端架构…...
C++炸弹小游戏
游戏效果 小人可以随便在一些元素(如石头,岩浆,水,宝石等)上跳跃,“地面”一直在上升,小人上升到顶部或者没有血的时候游戏结束(初始20点血),小人可以随意放炸…...
发送通知消息
目录 1 himall3.0商城源码 1.1 SendMessageOnOrderShipping 1.1.1 //发送通知消息 1.2 /// 所有订单是否都支付 1.2.1 //有待付款的订单,则未支付完成 himall3.0商城源码 public static List<InvoiceTitleInfo> GetInvoiceTitles(long userid) { re…...
Python报错:PermissionError: [Errno 13] Permission denied解决方案
Python报错:PermissionError: [Errno 13] Permission denied 翻译为:权限错误:[errno 13]权限被拒绝 错误产生的原因是文件无法打开,可能产生的原因是文件找不到,或者被占用,或者无权限访问,或者…...
【leetcode】第六章 二叉树part01
递归遍历 144. 二叉树的前序遍历 // 前序遍历 public List<Integer> preorderTraversal(TreeNode root) {List<Integer> res new ArrayList<>();preOrder(root, res);return res;}private void preOrder(TreeNode root, List<Integer> res) {if (ro…...
All In One!Meta发布SeamlessM4T,支持100种语言,35种语音、开源、在线体验!
多语言识别翻译的研究一直都是学术界研究的重点。目前全球有几千种语言,在全球化背景下不同语言人群之间的交流越来越密切,然而学习一门外语的成本是非常大的。前两年的研究主要集中在一对一、一对多的研究,然而当面对这么多的语言时…...
Python可视化工具库实战
Matplotlib Matplotlib 是 Python 的可视化基础库,作图风格和 MATLAB 类似,所以称为 Matplotlib。一般学习 Python 数据可视化,都会从 Matplotlib 入手,然后再学习其他的 Python 可视化库。 Seaborn Seaborn 是一个基于 Matplo…...
编解码视频测试序列集
最近测试解码器性能,搜集了一下可以免费的测试序列及,现在罗列如下,有很多需要翻墙: 1、h264的视频测试序列集 https://pi4.informatik.uni-mannheim.de/~kiess/test_sequences/download/ 2、HEVC测试序列 https://blog.csdn.net/…...
1 Hadoop入门
1.Hadoop是什么? (1)Hadoop是一个由Apache基金会所开发的分布式系统基础架构。 (2)主要解决,海量数据的存储和海量数据的分析计算问题。 (3)广义上来说,Hadoop通常是指一个更广泛的概念——Hadoop生态圈 2.Hadoop的优势 3 Hadoop组成 4 HDF…...
骨传导耳机哪款比较好,市面上最好的骨传导耳机分享
随着科技的日新月异,骨传导耳机也在不断更新换代。市场上涌现出许多品牌,这使得消费者在购买时感到困惑。别担心!我们为你整理了一些市场上最好的骨传导耳机品牌,希望能帮到你。现在,就让我们一起探索这些骨传导耳机的…...
centos7安装docker-compose—及常见错误排解
目录 一、Docker-Compose概述Compose有2个重要的概念:一、安装docker-compose1.从github上下载docker-compose二进制文件安装 二、Docker-compose实战 二、Dcoker-compose 不好下载,你直接使用docker 一个一个的安装使用dockerfile安装各种服务组件 一、…...
Stable Diffusion 文生图技术原理
图像生成模型简介 图片生成领域来说,有四大主流生成模型:生成对抗模型(GAN)、变分自动编码器(VAE)、流模型(Flow based Model)、扩散模型(Diffusion Model)。…...
Jumpserver堡垒机管理(安装和相关操作)-------从小白到大神之路之学习运维第89天
第四阶段 时 间:2023年8月28日 参加人:全班人员 内 容: Jumpserver堡垒机管理 目录 一、堡垒机简介 (一)运维常见背黑锅场景 (二)背黑锅的主要原因 (三)解决背黑…...
伦敦金走势多变怎么办
投资知识比较丰富的朋友,应该知道一个品种的价格过于波动,对投资者来说并是一件不友好的事情,因为频繁的价格变化,对于收益的稳定性会产生负面的影响,也可能让投资者的持仓陷入进退维谷的尴尬境地。 黄金作为贵金属市场…...
MybatisPlus-插件篇
文章目录 一、前言二、插件1、分页插件2.1.1、引入依赖2.1.1、配置分页插件2.1.3、使用分页方法 2、乐观锁插件2.1、引入依赖2.2、添加版本字段2.3、配置乐观锁插件2.4、执行更新操作 三、总结 一、前言 本文将详细介绍mybatisplus中常用插件的使用。 二、插件 1、分页插件 …...
数学建模:熵权法
🔆 文章首发于我的个人博客:欢迎大佬们来逛逛 熵权法 构建原始矩阵 D a t a Data Data 形状为 m ∗ n m *n m∗n ,其中 m m m 为评价对象, n n n 为评价指标。对 D a t a Data Data矩阵的指标进行正向化处理,得到…...
软件测试实训系统建设方案
一 、系统概述 软件测试实训系统是软件开发过程中的一项重要测试活动,旨在验证不同软件模块或组件之间的集成与交互是否正常。综合测试确保各个模块按照设计要求正确地协同工作,以实现整个软件系统的功能和性能。以下是软件测试实训系统的一般流程和步骤…...
部署 ssm 项目到云服务器上(购买云服务器 + 操作远程云服务器 + 服务器中的环境搭建 + 部署项目到服务器)
部署 Web 项目 1、获取 Linux 环境1.1、如何去买一个云服务器1.2、远程操作云服务器1.3、在 Linux 系统中搭建 Java Web 的运行环境。1)安装 JDK(使用包管理器 yum 来安装)2) 安装Tomcat3)安装 MySQL。 1.4、在云服务器…...
idea大量爆红问题解决
问题描述 在学习和工作中,idea是程序员不可缺少的一个工具,但是突然在有些时候就会出现大量爆红的问题,发现无法跳转,无论是关机重启或者是替换root都无法解决 就是如上所展示的问题,但是程序依然可以启动。 问题解决…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
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日构建) 问题现象 在项目开发过程中,提示一个依赖外部头文件的cpp源文件需要同步,点…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
LangFlow技术架构分析
🔧 LangFlow 的可视化技术栈 前端节点编辑器 底层框架:基于 (一个现代化的 React 节点绘图库) 功能: 拖拽式构建 LangGraph 状态机 实时连线定义节点依赖关系 可视化调试循环和分支逻辑 与 LangGraph 的深…...
通过MicroSip配置自己的freeswitch服务器进行调试记录
之前用docker安装的freeswitch的,启动是正常的, 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...
FFmpeg avformat_open_input函数分析
函数内部的总体流程如下: avformat_open_input 精简后的代码如下: int avformat_open_input(AVFormatContext **ps, const char *filename,ff_const59 AVInputFormat *fmt, AVDictionary **options) {AVFormatContext *s *ps;int i, ret 0;AVDictio…...
解析两阶段提交与三阶段提交的核心差异及MySQL实现方案
引言 在分布式系统的事务处理中,如何保障跨节点数据操作的一致性始终是核心挑战。经典的两阶段提交协议(2PC)通过准备阶段与提交阶段的协调机制,以同步决策模式确保事务原子性。其改进版本三阶段提交协议(3PC…...
