1

我正在为我的状态栏编写一个插件来打印 MPD 状态,目前使用的是libmpdclient库。如果 MPD 重新启动,它必须能够正确处理丢失的连接,但是mpd_connection_get_error对现有mpd_connection对象的简单检查不起作用——它只能在初始mpd_connection_new失败时检测到错误。

这是我正在使用的简化代码:

#include <stdio.h>
#include <unistd.h>
#include <mpd/client.h>

int main(void) {
    struct mpd_connection* m_connection = NULL;
    struct mpd_status* m_status = NULL;
    char* m_state_str;

    m_connection = mpd_connection_new(NULL, 0, 30000);

    while (1) {
        // this check works only on start up (i.e. when mpd_connection_new failed),
        // not when the connection is lost later
        if (mpd_connection_get_error(m_connection) != MPD_ERROR_SUCCESS) {
            fprintf(stderr, "Could not connect to MPD: %s\n", mpd_connection_get_error_message(m_connection));
            mpd_connection_free(m_connection);
            m_connection = NULL;
        }

        m_status = mpd_run_status(m_connection);
        if (mpd_status_get_state(m_status) == MPD_STATE_PLAY) {
            m_state_str = "playing";
        } else if (mpd_status_get_state(m_status) == MPD_STATE_STOP) {
            m_state_str = "stopped";
        } else if (mpd_status_get_state(m_status) == MPD_STATE_PAUSE) {
            m_state_str = "paused";
        } else {
            m_state_str = "unknown";
        }
        printf("MPD state: %s\n", m_state_str);
        sleep(1);
    }
}

当 MPD 在上述程序执行期间停止时,它会出现以下段错误:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00007fb2fd9557e0 in mpd_status_get_state () from /usr/lib/libmpdclient.so.2

我能想到的使程序安全的唯一方法是在每次迭代中建立一个新的连接,这是我希望避免的。但是,如果各个libmpdclient函数调用之间的连接丢失了怎么办?我应该多久检查一次,更重要的是如何检查连接是否仍然存在?

4

2 回答 2

2

我能找到真正有效的唯一方法(除了与每次运行重新建立连接)是使用idle 命令。如果mpd_recv_idle(或mpd_run_idle) 返回 0,这是一个错误条件,您可以将其作为释放连接并从那里运行的提示。这不是一个完美的解决方案,但它确实可以让您在运行之间保持实时连接,并且可以帮助您避免段错误(尽管我认为您不能完全避免它们,因为如果您发送命令并且 mpd 在您接收之前被杀死它,我很确定图书馆仍然存在段错误)。我不确定是否有更好的解决方案。如果有一种可靠的方法可以通过 API 检测您的连接是否仍然存在,那就太好了,但我找不到任何类似的东西。似乎 libmpdclient 不是为必须处理随时间上升和下降的 mpd 实例而构建的非常长的连接。

另一个较低级别的选项是使用套接字直接通过其协议与 MPD 交互,尽管这样做您可能会重新实现 libmpdclient 本身的大部分内容。

编辑:不幸的是,idle 命令确实会阻塞,直到发生某些事情,并且只要一个音轨持续存在,它就可以一直阻塞,所以如果你需要你的程序在此期间做其他事情,你必须找到一种方法来实现它异步或在另一个线程中。

于 2015-11-23T21:46:32.160 回答
0

假设“conn”是使用“mpd_connection_new”创建的连接:

if (mpd_connection_get_error(conn) == MPD_ERROR_CLOSED) {
    // mpd_connection_get_error_message(conn)
    // will return "Connection closed by the server"
}

您可以在几乎所有 libmpdclient 调用后运行此检查,包括“mpd_recv_idle”或(根据您的示例)“mpd_run_status”。

我正在使用 libmpdclient 2.18,这当然对我有用。

于 2020-06-29T00:35:39.837 回答