【问题标题】:C sendmsg() no buffer space availableC sendmsg() 没有可用的缓冲区空间
【发布时间】:2012-10-10 13:15:28
【问题描述】:

我不是 C 编程专家,但我正在尝试编写一个相当简单的程序,使用 sendmsg() 和 recvmsg() 在客户端和服务器之间发送消息(两者都在同一台机器上,所以基本上我是在向 localhost 发送消息)。

在初始化所需的结构(如在 iovec 和 msghdr 中)并成功将客户端连接到服务器后,我的 sendmsg() 调用失败并出现“没有可用的缓冲区空间”错误。

这是 linux man 报告的此类错误:

网络接口的输出队列已满。这一般表示接口已经停止发送,但可能是暂时拥塞造成的。 (通常情况下,这在 Linux 中不会发生。当设备队列溢出时,数据包会被静默丢弃。)

我在互联网上四处寻找,结果发现 sendmsg() 没有被广泛使用,没有人能与这种类型的错误联系起来。我发现的唯一有用的建议是检查是否有过多的打开套接字,但我总是关闭我创建的每个套接字。

所以我被困住了,主要是因为我是个菜鸟,我不知道该去哪里解决这类问题。

如果有人知道如何继续,那就太好了。 (请不要告诉我不要使用 sendmsg(),因为我工作的全部目的是理解这个系统调用,而不是向自己发送消息)

这是我目前在 pastebin 上编写的代码:clientserver

--已解决--

非常感谢。我已经能够解决这个问题并修复了我犯的其他错误,所以这里是 sendmsg() 和 recvmsg() 工作消息传递的功能代码:ClientServer

【问题讨论】:

  • 或unix域(或socketpair)?
  • 您的意思是ENOBUFS 错误,对吗?嗯,这确实很奇怪。您能否提供一个最小的测试用例,以便其他人可以尝试重现它?
  • 我使用面向连接的 AF_INET 套接字(类型 SOCK_STREAM),所以是 TCP。
  • 这是我目前所做的:客户端 --> link 服务器 --> link 这确实是基本代码,但正如我所说,我是菜鸟。
  • @xHawk 请注意,在您展示代码后,您获得实际答案的速度有多快。随意就 a) 谈论描述代码和 b) 实际代码的相对价值得出结论。尤其是当已知代码有一个或多个错误时...

标签: c


【解决方案1】:

正如其他人所指出的,iovlen 应该为 1。但是,您希望在初始化 mh 的某些字段之前将其清零,因为您可能会在未初始化的字段中发送垃圾并且系统调用会混淆。此外,设置 msg_name 和 msg_namelen 并没有什么意义,因为您已连接并且无论如何都无法改变将数据发送到何处的想法。

这在您的客户端代码中对我有用:

/* The message header contains parameters for sendmsg.    */
memset(&mh, 0, sizeof(mh));                                                                                                                                                                                                                                                                          
mh.msg_iov = iov;
mh.msg_iovlen = 1;

printf("mh structure initialized \n");

【讨论】:

  • 非常感谢代码和解释,这真的很有帮助。
  • 请不要memset 结构,而是显式初始化成员。使用memset 会假设值的二进制表示可能并不总是成立。
  • @SimonRichter 虽然这在理论上是正确的,但实际上我会说这不再重要了。我认为 sendmsg 工作的任何系统都不会有空指针或浮点数的非零位表示。很久以前,当 calloc 被添加到 C 标准时,替代位表示的战斗已经失败,然后由于其正式定义与其预期用途相冲突而变得无用,然后试图用脚注来修复。如果您像魔鬼拥护者一样阅读 C11,您会发现甚至有两个补码假设。
【解决方案2】:

msg_iovlen 字段包含 iov 数组中的元素数量,而不是其大小(以字节为单位)。

系统将以下未初始化的内存解释为 iov 元素,最终得到的数据包大于可用的套接字缓冲区空间,因此拒绝发送数据。

【讨论】:

    【解决方案3】:

    好的,所以在你的代码中我发现了这个:

    mh.msg_iovlen = sizeof(iov);
    

    这会将msg_iovlen 成员设置为struct iovec 的大小。但是文档说明了这个字段:

    size_t msg_iovlen; /* # msg_iov 中的元素 */

    所以你的代码是错误的,它告诉sendmsg() 它会发送比你实际初始化更多的元素。

    【讨论】:

      猜你喜欢
      • 2018-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-14
      • 2010-11-16
      • 2016-08-08
      • 1970-01-01
      • 2017-03-18
      相关资源
      最近更新 更多