12

我用纯 C 语言编写了这个小型服务器应用程序,它侦听给定端口中的传入连接,非常简单。

它使用通常的套接字初始化过程,创建到端口的socket()then bind(),说它的 a listen(),并无限循环select()等待传入的连接到accept()

一切都很好,就像一个魅力,除了如果我让这个东西运行几个月,监听端口会关闭,而应用程序服务器会一直运行而不知道它,因为我写它是为了相信监听套接字不会关闭,如果没有告诉。

所以问题是:为什么在我的应用程序不关心的情况下关闭端口,我能做些什么来防止它发生?

这是预期的行为吗?我应该检查某种异常还是在侦听套接字上进行“健康检查”以在必要时重新打开它?

代码:https ://gist.github.com/Havenard/e930be035a3bee75c018 (是的,我意识到我正在0用作错误提示,这是不好的做法和东西,但正如我在评论中解释的那样,它与问题无关,当我将套接字文件描述符设置为0它是为了停止循环并关闭应用程序)。

4

5 回答 5

6

我将从清理它开始:

  • 把它切割成更小的、可读的、可验证的、可测试的函数
  • 链表的使用看起来很乱;它可以简化很多,也许通过引入一些通用函数。
  • 用更易读的 ' ' 等价物替换所有愚蠢的 '\x20' 字符常量
  • 避免像这里这样的显式魔法常数if (n_case > 0) memcpy(nick, node->nick, (n_case > 32 ? 32 : n_case));;sizeof 是你的朋友。
  • 不要使用零作为未使用文件描述符的标记值;改用 -1。
  • 对大小和索引使用无符号类型;负索引会破坏内存,折叠无符号类型会很快失败。(failfast 是你的朋友)

这只是几个小时的编辑。

我的猜测是,在清理/重构之后,你的“bug”会神奇地浮出水面。

脚注:不,我不会为你做你的工作。不是为了100分,不是为了1000分。请收拾你自己的烂摊子。

于 2013-03-06T19:40:42.847 回答
2

这个答案主要是对你打电话的地方的代码审查close()

第 330 行:您关闭了套接字,但不要像在代码中的其他地方那样立即继续。这可能会导致奇怪的行为。

第 928 行:在大多数地方,您0在调用close(). 你不会在这个电话之后。

第 1193 行:与第 928 行相同的注释。

第 1195 行:与第 928 行相同的注释。

第 1218 行:与第 928 行相同的注释。

第 1234 行:与第 928 行相同的注释。

第 1236 行:与第 928 行相同的注释。

当我编译带有完整警告的代码时,我看到编译器注意到函数声明返回值的许多地方,但没有返回值。

x.c:582: warning: no return statement in function returning non-void
x.c:591: warning: no return statement in function returning non-void
x.c:598: warning: no return statement in function returning non-void
x.c:609: warning: no return statement in function returning non-void
x.c:620: warning: no return statement in function returning non-void
x.c:728: warning: no return statement in function returning non-void
x.c:779: warning: no return statement in function returning non-void

如其他帖子所述,还有许多其他问题。

至于调试这个问题,如果我怀疑绑定套接字被提前关闭,我会close()用我自己的版本拦截调用,该版本断言正在关闭的描述符不应该与绑定套接字匹配。

然而,正如 wildplasser 所指出的,select()如果它被关闭,它将返回一个关于无效描述符的错误。

于 2013-03-12T21:25:36.720 回答
1

错误是您使用 0 作为无效的文件描述符。0 完全有效,通常是标准输入。然后在信号处理程序中将侦听器设置为 0。然后您使用 0 作为无 fd,并且在某些时候您在某个套接字上执行 close(0),有一些分支执行 close(fd) 而不检查它是否为 0,并且有效地关闭了侦听器。阻止侦听器工作的另一个可能选项是溢出积压。

还有一个问题 - 对 fds 使用 unsigned int。系统调用在错误时返回 -1 ... 如果分配给 unsigned int struct identd_node -> unsigned int 句柄,则不会检测到该错误;结构线程节点->无符号整数skt_clnt,skt_serv;

于 2013-03-10T22:27:37.687 回答
0

看起来您的代码需要有 2 个连续错误才能导致失败。

如果您从选择中收到错误,为什么不立即打印出原因呢?

在第 281 行, printf errno/perror 找出问题所在?

于 2013-03-07T12:50:11.927 回答
0

尽管系统不应该像描述的那样运行,但它有时会这样做。对于服务器系统,您通常需要在外部(从脚本)或从代码中的特殊线程执行运行状况检查调用。

因此,如果您检测到连续几次尝试都无法连接到服务器(由于可能的过载情况而需要很少),您可以考虑套接字损坏并重新创建它或重新启动服务器。

于 2013-03-13T17:32:57.563 回答