libircclient:绝对不可能调试

时间:2015-04-25 21:37:16

标签: c++ irc

我通常不会发布问题的类型,而更多的是搜索为什么某些事情不能先发挥作用,但这次我做了我能做的一切,而我却无法弄清楚有什么不对。

所以这就是事情:

我目前正在编写一个IRC Bot,我正在使用libircclient这个小型C库来处理IRC连接。它的工作非常好,它完成了工作并且有点易于使用,但是......

我连接到两台不同的服务器,因此我使用自定义网络环路,它使用select功能。在我的个人电脑上,这个循环没问题,一切都很好。

但是(这就是问题),在我的远程服务器上,托管机器人,我可以连接到一台服务器而不是另一台服务器。

我试图调试我能做的一切。我甚至去研究了libircclient的来源,看看它是如何工作的,并把一些printfs放在我可能的地方,我可以看到它来自哪里,但我不明白为什么会这样做。

所以这里是服务器的代码(irc_session_t对象是封装的,但它通常很容易理解。如果你愿意,可以随意询问更多的信息):

// Connect the first session
first.connect();

// Connect the osu! session
second.connect();

// Initialize sockets sets
fd_set sockets, out_sockets;

// Initialize sockets count
int sockets_count;

// Initialize timeout struct
struct timeval timeout;

// Set running as true
running = true;

// While the server is running (Which means always)
while (running)
{
    // First session has disconnected
    if (!first.connected())
        // Reconnect it
        first.connect();

    // Second session has disconnected
    if (!second.connected())
        // Reconnect it
        second.connect();

    // Reset timeout values
    timeout.tv_sec = 1;
    timeout.tv_usec = 0;

    // Reset sockets count
    sockets_count = 0;

    // Reset sockets and out sockets
    FD_ZERO(&sockets);
    FD_ZERO(&out_sockets);

    // Add sessions descriptors
    irc_add_select_descriptors(first.session(), &sockets, &out_sockets, &sockets_count);
    irc_add_select_descriptors(second.session(), &sockets, &out_sockets, &sockets_count);

    // Select something. If it went wrong
    int available = select(sockets_count + 1, &sockets, &out_sockets, NULL, &timeout);

    // Error
    if (available < 0)
        // Error
        Utils::throw_error("Server", "run", "Something went wrong when selecting a socket");

    // We have a socket
    if (available > 0)
    {
        // If there was something wrong when processing the first session
        if (irc_process_select_descriptors(first.session(), &sockets, &out_sockets))
            // Error
            Utils::throw_error("Server", "run", Utils::string_format("Error with the first session: %s", first.get_error()));

        // If there was something wrong when processing the second session
        if (irc_process_select_descriptors(second.session(), &sockets, &out_sockets))
            // Error
            Utils::throw_error("Server", "run", Utils::string_format("Error with the second session: %s", second.get_error()));
    }

此代码中的问题是这一行:

irc_process_select_descriptors(second.session(), &sockets, &out_sockets)

在第一次调用时始终返回错误,并且仅针对一台服务器。奇怪的是,在我的Windows计算机上,它完美运行,而在Ubuntu服务器上,它只是不想要,而我只是无法理解为什么。

我做了一些深入的调试,我看到libircclient这样做了:

if (session->state == LIBIRC_STATE_CONNECTING && FD_ISSET(session->sock, out_set))

这就是一切都出错的地方。会话状态正确设置为LIBIRC_STATE_CONNECTING,但第二件事FD_ISSET(session-&gt; sock,out_set)始终返回false。它在第一个会话中返回true,但对于第二个会话,从不返回。

两台服务器是irc.twitch.tv:6667和irc.ppy.sh:6667。服务器设置正确,服务器密码也正确,因为我的个人计算机上的一切正常。

很抱歉很长的帖子。

提前致谢!

1 个答案:

答案 0 :(得分:0)

好的,经过几个小时的调试,我终于遇到了问题。

因此,当连接会话时,它将进入LIBIRC_STATE_CONNECTING状态,然后在调用irc_process_select_descriptors时,它将检查:

if (session->state == LIBIRC_STATE_CONNECTING && FD_ISSET(session->sock, out_set))

问题是select()会改变套接字集,并会删除所有不相关的集合。

因此,如果服务器在调用irc_process_select_descriptors之前没有发送任何消息,则FD_ISSET将返回0,因为select()认为此套接字不相关。

我通过写

来修复它
if (session->state == LIBIRC_STATE_CONNECTING)
{
    if(!FD_ISSET(session->sock, out_set))
        return 0;

    ...
}

因此它会使程序等到服务器向我们发送任何内容。

很抱歉没有检查过所有内容!