我通常不会发布问题的类型,而更多的是搜索为什么某些事情不能先发挥作用,但这次我做了我能做的一切,而我却无法弄清楚有什么不对。
所以这就是事情:
我目前正在编写一个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。服务器设置正确,服务器密码也正确,因为我的个人计算机上的一切正常。
很抱歉很长的帖子。
提前致谢!
答案 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;
...
}
因此它会使程序等到服务器向我们发送任何内容。
很抱歉没有检查过所有内容!