PING[ARC2]: Heartbeat failed to connect to standby 'gqtzdb_dg'. Error is 16047

本文记录了一次DataGuard配置过程中遇到的同步问题及其解决过程。主要介绍了如何通过查看错误日志定位到DGID不匹配的问题,并给出了修改db_unique_name参数的具体步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

PING[ARC2]: Heartbeat failed to connect to standby 'gqtzdb_dg'. Error is 16047

Posted on 2017-07-03 18:42 会飞的板儿 阅读(94) 评论(0) 编辑 收藏

  Data Guard搭建完毕之后,执行开启归档路径2,结果发现不同步,

SQL> alter system set log_archive_dest_state_2=enable;

  查看错误日志,发现有PING[ARC2]: Heartbeat failed to connect to standby 'gqtzdb_dg'. Error is 16047.的报错:

[oracle@KG-ORA-01 trace]$ tail -100f alert_gqtzdb.log 
Mon Jul 03 18:19:10 2017
Using STANDBY_ARCHIVE_DEST parameter default value as /oradata/gqtzdb/archivelog
ALTER SYSTEM SET log_archive_dest_state_2='ENABLE' SCOPE=BOTH;
Mon Jul 03 18:19:10 2017
PING[ARC2]: Heartbeat failed to connect to standby 'gqtzdb_dg'. Error is 16047.

  接着查看v$archive_dest视图,查看是否能找到原因,结果发现如下报错:

复制代码

SQL> select dest_id,error from v$archive_dest;

   DEST_ID ERROR
---------- -----------------------------------------------------------------
         1
         2 ORA-16047: DGID mismatch between destination setting and target
           database

复制代码

  很明显,DGID不一样,去备库查看参数db_unique_name参数:

SQL> show parameter db_unique_name

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
db_unique_name                       string      gqtzdb

  发现db_unique_name参数没有修改,仍然是主库的值,速度改过来,并重启备库:

1

2

3

4

5

6

7

8

9

10

SQL> alter system set db_unique_name='gqtzdb_dg' scope=both;

alter system set db_unique_name='gqtzdb_dg' scope=both

                 *

ERROR at line 1:

ORA-02095: specified initialization parameter cannot be modified

 

 

SQL> alter system set db_unique_name='gqtzdb_dg' scope=spfile;

 

System altered.

  然后再在主库开启归档路径2,在备库运行命令,查看同步状态:

复制代码

SQL> alter database recover managed standby database using current logfile disconnect from session;

Database altered.

SQL> select process,client_process,sequence#,status from v$managed_standby;

PROCESS   CLIENT_P  SEQUENCE# STATUS
--------- -------- ---------- ------------
ARCH      ARCH              0 CONNECTED
ARCH      ARCH              0 CONNECTED
ARCH      ARCH              0 CONNECTED
ARCH      ARCH              0 CONNECTED
RFS       UNKNOWN           0 IDLE
RFS       LGWR             24 IDLE
RFS       UNKNOWN           0 IDLE
RFS       UNKNOWN           0 IDLE
MRP0      N/A              11 APPLYING_LOG

9 rows selected.

转载于:https://my.oschina.net/rootliu/blog/1557755

websocket_tpye = websocket_tls; if(m_init) { m_init = false; _client_tls.clear_access_channels(websocketpp::log::alevel::all);//设置日志级别 _client_tls.clear_error_channels(websocketpp::log::elevel::all);//屏蔽某个级别的日志 _client_tls.init_asio(); _client_tls.start_perpetual(); _client_tls.set_tls_init_handler(bind(&on_tls_init1, hostname.c_str(), ::_1)); client_thread = websocketpp::lib::make_shared<websocketpp::lib::thread>(&client_tls::run, &_client_tls); } websocketpp::lib::error_code ec; client_tls::connection_ptr con = _client_tls.get_connection(uri, ec); if (ec) { QDEBUG<<" could not create connection because:"<<QString::fromStdString(ec.message()); return -1; } metadata_tls = websocketpp::lib::make_shared<connection_metadata_tls>(con->get_handle(), uri); if(QString::fromStdString(password).isEmpty()) { } else { std::string val = "Basic " + base64_encode(QString::fromStdString(devnumber)+":"+QString::fromStdString(password)); con->append_header("Authorization", val); } con->set_open_handler(websocketpp::lib::bind( &connection_metadata_tls::on_open, metadata_tls, &_client_tls, websocketpp::lib::placeholders::_1 )); con->set_fail_handler(websocketpp::lib::bind( &connection_metadata_tls::on_fail, metadata_tls, &_client_tls, websocketpp::lib::placeholders::_1 )); con->set_close_handler(websocketpp::lib::bind( &connection_metadata_tls::on_close, metadata_tls, &_client_tls, websocketpp::lib::placeholders::_1 )); con->set_message_handler(websocketpp::lib::bind( &connection_metadata_tls::on_message, metadata_tls, websocketpp::lib::placeholders::_1, websocketpp::lib::placeholders::_2 )); _client_tls.connect(con); } else {//ws websocket_tpye = websocket_no_tls; if(m_init) { m_init = false; _client_no_tls.clear_access_channels(websocketpp::log::alevel::all); _client_no_tls.clear_error_channels(websocketpp::log::elevel::all); _client_no_tls.init_asio(); _client_no_tls.start_perpetual(); client_thread = websocketpp::lib::make_shared<websocketpp::lib::thread>(&client_no_tls::run, &_client_no_tls); } websocketpp::lib::error_code ec; client_no_tls::connection_ptr con = _client_no_tls.get_connection(uri, ec); if (ec) { QDEBUG<<" could not create connection because:"<<QString::fromStdString(ec.message()); return -1; } metadata_no_tls = websocketpp::lib::make_shared<connection_metadata_no_tls>(con->get_handle(), uri); if(QString::fromStdString(password).isEmpty()) { } else { std::string val = "Basic "+base64_encode(QString::fromStdString(devnumber)+":"+QString::fromStdString(password)); con->append_header("Authorization", val); } con->set_open_handler(websocketpp::lib::bind( &connection_metadata_no_tls::on_open, metadata_no_tls, &_client_no_tls, websocketpp::lib::placeholders::_1 )); con->set_fail_handler(websocketpp::lib::bind( &connection_metadata_no_tls::on_fail, metadata_no_tls, &_client_no_tls, websocketpp::lib::placeholders::_1 )); con->set_close_handler(websocketpp::lib::bind( &connection_metadata_no_tls::on_close, metadata_no_tls, &_client_no_tls, websocketpp::lib::placeholders::_1 )); con->set_message_handler(websocketpp::lib::bind( &connection_metadata_no_tls::on_message, metadata_no_tls, websocketpp::lib::placeholders::_1, websocketpp::lib::placeholders::_2 )); _client_no_tls.connect(con); // websocketpp::connection_hdl hdl=con->get_handle(); // qDebug()<<"111"<<hdl._empty(); // _client_no_tls.ping(hdl,"heartbeat",ec); // SendPing(hdl); } } Linux QT4环境下,如何在此段代码中实现发送ping
最新发布
07-04
<think>我们正在使用WebSocket++库,并且需要在QT4环境下实现发送Ping消息的功能。WebSocket++提供了发送Ping帧的接口。根据WebSocket++文档,我们可以使用`connection`对象的`ping`方法发送Ping消息。步骤:1.获取当前连接的connection_ptr。2.调用connection_ptr的`ping`方法,参数可以是一个字符串(作为Ping的有效载荷,可选)。注意:WebSocket++中,Ping消息可以携带一个可选的字符串作为负载。但是,根据规范,负载长度不能超过125字节。在QT4环境下,我们需要确保在正确的线程中调用WebSocket++的方法,因为WebSocket++不是线程安全的,通常需要在它所在的IO线程中操作。由于我们的代码可能使用了多线程(例如,QT的线程),我们需要考虑线程安全。在WebSocket++中,我们可以使用`post`方法将操作投递到WebSocket++的内部io_service中执行。示例代码:假设我们有一个WebSocket连接对象(类型为`websocketpp::connection_hdl`),我们可以这样发送Ping: ```cpp//获取connection_ptrwebsocketpp::connection_hdl hdl =...;//你的连接句柄websocketpp::server::connection_ptr con= m_server.get_con_from_hdl(hdl, lock);if (con){//发送Ping,可以指定一个字符串作为负载,例如空字符串或"heartbeat"con->ping("heartbeat");} ```但是,如果我们在另一个线程中(非WebSocket++的io_service线程),我们需要使用`post`方法: ```cppm_server.get_io_service().post(boost::bind(&websocketpp::connection<config>::ping, con, "heartbeat", websocketpp::frame::opcode::value::PING)); ```然而,在WebSocket++的0.8.x版本中,我们可以更简单地使用`server`的`send`方法,但发送Ping有专门的`ping`方法。另外,我们也可以使用`server`对象的`ping`方法,它内部会处理线程安全: ```cppm_server.ping(hdl, "heartbeat"); ```这个`ping`方法会检查当前线程是否是io_service线程,如果不是,则会使用`post`投递。因此,推荐使用`m_server.ping(hdl,payload)`来发送Ping消息。在QT4环境中,我们可能需要在某个定时器中定期发送Ping以保持连接。我们可以使用QTimer,然后在定时器的槽函数中调用发送Ping的函数。但是注意:我们不能直接在一个QT的定时器槽函数中操作WebSocket++对象,因为WebSocket++的io_service可能运行在另一个线程。因此,我们需要使用`m_server.ping`,它会自动处理线程切换。示例:1.在某个管理类中,我们设置一个定时器,并连接定时器的timeout信号到一个槽函数。2.在槽函数中,遍历所有连接(或者对某个特定连接)调用`m_server.ping`。注意:我们需要保存所有活跃连接的句柄(hdl)。WebSocket++的server对象内部有连接列表,但直接遍历需要加锁,且不推荐。通常,我们可以在连接建立时保存句柄,断开时移除。实现:我们可以维护一个连接句柄的列表(例如`std::set<websocketpp::connection_hdl,std::owner_less<websocketpp::connection_hdl>>`),并使用弱指针(因为句柄是弱指针)或者使用`connection_hdl`的弱引用特性。注意,`connection_hdl`是一个弱指针,所以我们需要在发送前检查连接是否还存在。另一种方法是,在每次发送Ping时,我们遍历服务器当前的所有连接。WebSocket++没有直接提供获取所有连接句柄的接口,但我们可以通过继承server类并重写连接事件来维护连接列表。通常,我们会在on_open事件中将连接句柄加入一个集合,在on_close事件中移除。示例代码片段: ```cppclass my_server: publicwebsocketpp::server<websocketpp::config::asio>{ public:void on_open(websocketpp::connection_hdl hdl){//将hdl加入连接集合m_connections.insert(hdl);}void on_close(websocketpp::connection_hdl hdl){//从连接集合中移除hdlm_connections.erase(hdl);}void send_ping_to_all(conststd::string&payload){std::set<websocketpp::connection_hdl,std::owner_less<websocketpp::connection_hdl>>::iteratorit;for(it= m_connections.begin();it !=m_connections.end(); ++it){//使用ping方法,它会检查连接是否有效,并且线程安全ping(*it, payload);}} private:std::set<websocketpp::connection_hdl,std::owner_less<websocketpp::connection_hdl>>m_connections;}; ```然后,在定时器槽函数中,调用`send_ping_to_all`。但是,注意:`m_connections`需要线程安全,因为on_open和on_close事件是在io_service线程中调用的,而定时器槽函数可能是在QT的主线程(或其他线程)中。因此,我们需要对`m_connections`进行加锁保护。我们可以使用互斥锁:```cpp#include<mutex>class my_server :public websocketpp::server<websocketpp::config::asio> {public:voidon_open(websocketpp::connection_hdlhdl) {std::lock_guard<std::mutex> lock(m_connection_mutex);m_connections.insert(hdl);}voidon_close(websocketpp::connection_hdlhdl) {std::lock_guard<std::mutex> lock(m_connection_mutex);m_connections.erase(hdl);}voidsend_ping_to_all(conststd::string&payload){std::lock_guard<std::mutex>lock(m_connection_mutex);std::set<websocketpp::connection_hdl,std::owner_less<websocketpp::connection_hdl>>::iteratorit;for(it= m_connections.begin();it !=m_connections.end(); ++it){//注意:这里我们直接调用server的ping方法,它是线程安全的(内部会检查是否在io_service线程,否则会post)ping(*it,payload);}}private:std::mutex m_connection_mutex;std::set<websocketpp::connection_hdl,std::owner_less<websocketpp::connection_hdl>>m_connections;}; ```然后,我们在QT的定时器槽函数中调用`send_ping_to_all`。设置定时器: ```cpp//在某个QT类中QTimer *timer= newQTimer(this);connect(timer,SIGNAL(timeout()), this, SLOT(onPingTimer()));timer->start(5000);//5秒一次//槽函数void MyClass::onPingTimer() {m_server.send_ping_to_all("heartbeat");} ```注意:`m_server`是`my_server`的实例,并且需要确保`m_server`的io_service在运行(通常在一个单独的线程中运行)。另一种做法:我们也可以不在定时器里遍历所有连接,而是每个连接单独设置一个定时器,但这样会消耗更多资源。总结:在QT4环境下,使用WebSocket++发送Ping消息的步骤:1.创建一个继承自`websocketpp::server`的类,并重写`on_open`和`on_close`来维护当前连接句柄的集合(需要加锁)。2.提供一个发送Ping给所有连接的函数(内部遍历连接集合并调用`ping`方法)。3.使用QT的QTimer定时触发发送Ping。注意:WebSocket++的io_service需要在一个单独的线程中运行,通常我们会启动一个线程来运行`run()`方法。关于线程:由于QT4的环境,我们需要注意跨线程调用。WebSocket++的`ping`方法内部已经处理了线程安全,所以我们可以安全地从QT的线程调用。另外,如果只需要对某个特定连接发送Ping,则可以直接保存该连接的句柄,然后在定时器槽函数中调用`m_server.ping(hdl, payload)`。以上就是在QT4环境下使用WebSocket++库实现发送WebSocket Ping消息的方法。相关问题:1.如何在WebSocket++中处理Pong响应?2.如何设置WebSocket++的定时器以定期发送Ping?3.在QT4中如何安全地停止WebSocket++服务器?4.WebSocket++中如何设置最大消息大小?5.如何处理WebSocket++中的多线程同步问题?</think>### 在QT4中使用WebSocket++实现Ping消息发送 在QT4环境下使用WebSocket++库实现WebSocket Ping消息发送,需要结合WebSocket++的底层API和QT的事件循环机制。以下是关键步骤和代码实现: #### 核心步骤 1. **创建定时器**:使用QT的`QTimer`定期发送Ping消息 2. **获取连接句柄**:通过服务器对象获取活动连接 3. **发送Ping帧**:调用WebSocket++的`ping()`方法 4. **处理线程安全**:确保跨线程操作的安全性 #### 代码实现 ```cpp #include <websocketpp/server.hpp> #include <websocketpp/config/asio_no_tls.hpp> #include <QTimer> typedef websocketpp::server<websocketpp::config::asio> server; using websocketpp::lib::placeholders::_1; using websocketpp::lib::bind; class WebSocketServer : public QObject { Q_OBJECT public: WebSocketServer(uint16_t port) : m_port(port) { // 初始化服务器 m_server.init_asio(); m_server.set_open_handler(bind(&WebSocketServer::on_open, this, _1)); m_server.set_close_handler(bind(&WebSocketServer::on_close, this, _1)); // 设置定时器(每30秒发送Ping) m_pingTimer = new QTimer(this); connect(m_pingTimer, SIGNAL(timeout()), this, SLOT(send_pings())); m_pingTimer->start(30000); // 30秒间隔 } void start() { m_server.listen(m_port); m_server.start_accept(); m_server.run(); } private slots: void send_pings() { // 遍历所有活动连接发送Ping std::unique_lock<std::mutex> lock(m_connectionMutex); for (auto& hdl : m_connections) { if (auto conn = m_server.get_con_from_hdl(hdl)) { conn->ping(""); // 发送空负载的Ping帧 } } } private: void on_open(websocketpp::connection_hdl hdl) { std::unique_lock<std::mutex> lock(m_connectionMutex); m_connections.insert(hdl); } void on_close(websocketpp::connection_hdl hdl) { std::unique_lock<std::mutex> lock(m_connectionMutex); m_connections.erase(hdl); } server m_server; uint16_t m_port; QTimer* m_pingTimer; std::set<websocketpp::connection_hdl, std::owner_less<websocketpp::connection_hdl>> m_connections; std::mutex m_connectionMutex; // 保护连接集合的互斥锁 }; ``` #### 关键点说明 1. **定时器机制**: - 使用`QTimer`定时触发`send_pings()`槽函数 - 时间间隔根据需求调整(示例为30秒) 2. **连接管理**: - 在`on_open`和`on_close`回调中维护活动连接集合 - 使用`std::mutex`确保线程安全(WebSocket++在独立线程运行) 3. **Ping发送**: - `conn->ping("")`发送标准Ping帧 - 可选添加负载数据(如`ping("heartbeat")`),但需遵守125字节限制 4. **Pong处理**: - 可添加Pong处理器验证连接活性: ```cpp m_server.set_pong_handler([this](auto hdl, auto msg) { qDebug() << "Received pong: " << msg.c_str(); }); ``` #### 注意事项 1. **线程安全**:所有对`m_connections`的访问必须加锁 2. **资源释放**:在析构函数中停止定时器和服务器 3. **QT版本兼容**:WebSocket++需要C++11支持,需在.pro文件中添加: ```qmake CONFIG += c++11 LIBS += -lboost_system -lboost_random ``` 4. **心跳策略**:可根据需求调整Ping频率,推荐5-60秒[^1] --- ### 相关问题 1. **如何检测WebSocket连接断开?** WebSocket++会自动触发`close_handler`,也可通过Ping/Pong超时检测(需实现超时逻辑)[^2] 2. **如何处理Ping/Pong的负载数据?** 负载可以是任意字符串(最大125字节),常用于携带状态信息或时间戳 3. **如何优化多连接场景下的性能?** 使用连接池和异步IO,避免在定时器中阻塞主线程 4. **QT4与WebSocket++的兼容性问题有哪些?** 需注意信号/槽线程安全和C++11编译选项的设置 5. **如何实现双向心跳机制?** 可结合`ping()`和`set_pong_handler()`,添加超时计时器自动断开无响应连接[^3] [^1]: WebSocket RFC 6455规范要求Ping帧长度≤125字节 [^2]: WebSocket++文档中连接生命周期管理 [^3]: QT WebSocket心跳最佳实践
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值