1

现在我有一个 C++ 客户端应用程序,它使用 mysql.h 连接到 MYSQL 数据库,并且必须执行一些逻辑以防断开连接。我想知道这是否是在我的客户端断开连接的情况下重新连接到 MYSQL 数据库的最佳方式。

bool MYSQL::Reconnect(const char *host, const char *user, const char *passwd, const char *db)
{
bool out = false;

pid_t command_pid = fork();
if (command_pid == 0)
{
    while(1)
    {
        sleep(1);
        if (mysql_real_connect(&m_mysql, host, user, passwd, db, 0, NULL, 0) == NULL )
        {
            fprintf(stderr, "Failed to connect to database: Error: %s\n",
            mysql_error(&m_mysql));
        }
        else
        {
            m_connected = true;
            out = true;
            break;
        }
    }
    exit(0);
}

if (command_pid < 0)
    fprintf(stderr, "Could not fork process[reconnect]: %s\n", mysql_error(&m_mysql));

return out;
}

现在我接受了我所有的参数并进行了分叉。子进程每秒都尝试使用 sleep() 语句重新连接。这是一个好方法吗?谢谢

4

3 回答 3

4

抱歉,Kaiser Wilhelm,您的代码并没有按照您的想法执行。

从本质上讲,您试图将分叉视为线程,但事实并非如此。

当你 fork 一个子进程时,父进程被完全克隆,包括文件和套接字描述符,这就是你的程序连接到 MySQL 数据库服务器的方式。也就是说,当您分叉时,父子节点都将拥有与数据库服务器的相同连接的自己的副本。我假设父级仅Reconnect()在看到连接断开时才调用此方法,并停止使用其现已失效的 MySQL 连接对象的副本m_mysql。如果是这样,当您开始重新连接操作时,连接的父级副本与客户端的副本一样无用。

事实是,反过来也不是这样:一旦孩子设法重新连接到数据库服务器,父母的连接对象仍然失效。孩子所做的任何事情都不会传播给父母。在分叉之后,这两个进程完全独立,除非它们可能会尝试访问它们最初共享的某些 I/O 资源。例如,如果您Reconnect()在连接建立时调用此函数并继续使用父级中的连接,则子级尝试与同一连接上的数据库服务器通信会混淆mysqldor libmysqlclient,可能会导致数据损坏或崩溃。

如上所述,一种解决方案是使用线程而不是分叉。但是,请注意在 MySQL C API 中使用线程的许多问题。

如果可以选择,我宁愿使用异步 I/O 在应用程序的主线程中进行后台连接尝试,但 MySQL C API 不允许这样做。

似乎您在尝试重新连接数据库服务器时试图避免阻塞主应用程序线程。通过将连接超时设置为 1 秒,无论如何您都可以避免同步执行此操作,当 MySQL 服务器与客户端位于同一台机器或同一 LAN 上时,这很好。如果你可以容忍你的主线程阻塞长达一秒钟以导致连接尝试失败——最坏的情况发生在服务器位于单独的机器上并且它在物理上断开连接或防火墙时——这可能是比线程更清洁的解决方案。如果服务器机器仍在运行并且端口没有防火墙,例如当它重新启动并且 TCP/IP 堆栈 [仍然] 启动时,连接尝试可能会更快失败。

于 2011-08-10T17:14:49.440 回答
0

据我所知,这并没有达到您的预期。

逻辑问题

Reconnect根本不会“在断开连接的情况下执行一些逻辑”。

它一遍又一遍地尝试连接,直到成功,然后停止。就是这样。永远不会再次检查连接的状态。如果连接断开,则此代码对此一无所知

技术问题

还要密切关注沃伦提出的技术问题。

于 2011-08-10T17:24:55.070 回答
-2

当然,完全没问题。您可能想考虑用类似的while ( 1 )东西替换循环

  while ( NULL == mysql_real_connect( ... )) {
    sleep( 1 );
    ... 
  }

这是一种通过实践学习的习语,但据我所知,您的代码工作得很好。不要忘记在while循环中放置一个计数器。

于 2011-08-08T18:44:38.537 回答