【问题标题】:Unix Domain : connect() : No such file or directoryUnix域:connect():没有这样的文件或目录
【发布时间】:2012-07-24 13:09:29
【问题描述】:

如标题所述,我的 connect() 调用具有相应地址的 unix 域类型套接字会导致错误 ENOENT: no such file or directory

正确初始化了两个套接字,并相应地创建和绑定了套接字文件。服务器和客户端套接字在不同的进程中运行,尽管客户端进程是 fork()-ed 和 execl()-ed。这也是我解析客户端和服务器套接字地址的方式,我用它来设置客户端套接字。服务器进程正在使用 pthreads。

这是我的 connect() 尝试:

struct sockaddr_un address;
address.sun_family = AF_UNIX;
memcpy(address.sun_path, filepath.c_str(), filepath.length());
address.sun_path[filepath.length()] = '\0';

if(-1 == connect(this->unix_domain_descriptor_.descriptor(),       \
                (struct sockaddr*)&address,                       \
                size))
{
    global::ExitDebug(-1, "connect() failed", __FILE__, __LINE__);
    return -1;
}

我尝试了不同的大小值,例如:

//  this is from unix(7) man page. It doesn't work neither with nor without "+1"
socklen_t size =  offsetof(struct sockaddr_un, sun_path);
          size += strlen(address.sun_path) + 1;

//  this is from one of my books about linux programming
socklen_t size = sizeof(address);

//  this is from a sample code which I found at the internet
socklen_t size = sizeof(address.sun_family) + strlen(address.sun_path);

//  Update 1: 
socklen_t size = SUN_LEN(&address);

//  this is what I tried out after looking into the declaration
//  of struct sockaddr_un
socklen_t size = strlen(address.sun_path);

令人惊讶的是,除了最后一个初始化之外,所有初始化都会导致 connect() 出现 EINVAL: invalid argument 错误,并且我得到 ENOENT: no such file 或目录只有最后一个。我什至尝试了互联网上的整个示例,但没有成功。显然,用 size_t 或 int 交换 socklen_t 并没有改变任何东西。

我已经检查过了:

  • address.sun_path 包含从根目录开始的正确套接字文件路径
  • address.sun_path 的长度为 61 个字符
  • address.sun_family 设置为 AF_UNIX/AF_LOCAL
  • address.sun_family 大小为 2 个字节
  • 创建和绑定两个套接字时没有错误
  • 服务器套接字处于监听状态
  • sizeof(address) 按原样返回 110

现在我想知道为什么手册页示例不起作用,以及是否有未在linux.die.netwww.kernel.org 更新的更改。如果相关的话,我的操作系统是 Debian Squeeze。

任何想法我做错了什么?以及如何解决?如果您需要更多代码或有疑问,请随时问我(虽然我可能不需要说明这一点,但这是我在这里的第一篇文章>.

顺便说一句,对不起我的英语不好

更新 2

解决了。为了清楚起见,我将在下面的额外答案中发布它。

【问题讨论】:

  • strcpy 代替memcpy 和手动放置空终止符怎么样?
  • 感谢您的回复。我刚才试了一下,没变。顺便说一句,空终止符已经手动设置。
  • die.net 是一个糟糕的网站,其中包含过时的信息和大量广告。由于大量的 SEO,它得以幸存——仅此而已。我建议你永远不要使用它。
  • 谢谢。无论如何,我更喜欢 www.kernel.org。你会推荐其他页面吗?也许我可以在那里找到一些东西......
  • 更新后你的短语“除了最后一个”不再成立,是吗?

标签: c++ unix-socket


【解决方案1】:

在确定我正确处理了套接字之后,我稍微修改了 connect() 的代码,现在它可以工作了。我刚刚在我的变量声明之后添加了这一行:

memset(&address, 0, sizeof(struct sockaddr_un));

有谁知道为什么我需要将整个变量设置为 0 才能使其工作?我应该在新主题中问这个问题还是可以在这里问这个问题?

【讨论】:

  • struct sockaddr_un 中有一些字段可能会被传递它的函数读取。如果这些值未初始化,则将发生未定义的行为。此外,其中许多值默认为0,如果未正确初始化,则可能具有无效值。或者,如果它们是指针,则该函数将取消引用 NULL 指针。
  • 是的,这就是为什么我要设置我需要的所有变量,甚至是默认值。但是你明确指出这一点很好:D
【解决方案2】:

引用glibc manual:

你应该计算一个套接字地址的 LENGTH 参数 本地命名空间作为sun_family 组件大小的总和 和文件名的字符串长度(不是分配大小!) 细绳。这可以使用宏 SUN_LEN 来完成:

  • 宏:int SUN_LEN (_struct sockaddr_un *_ PTR)
    宏计算本地套接字地址的长度 命名空间。

下面的example 使用了一个你说它失败的计算:

size = (offsetof (struct sockaddr_un, sun_path)
       + strlen (name.sun_path) + 1);

但是你应该试试那个宏。如果发生了一些变化,或者示例错误,那么该宏仍然很有可能按预期工作。如果是这样,你可以看看它的内脏。乍一看,在我看来,宏缺少所有示例中使用的+ 1 部分。这与手册中的警告相匹配,使用“not分配大小!”正如你的帖子所说,如果没有+ 1,这也不起作用,但机会很小。

出于好奇,路径的长度是多少?您是否检查过结构中提供的字段是否足够大以容纳它?您的实现中的sizeof(address.sun_path) 是什么?我想知道您是否可能正在复制到未保留的内存,并且在下一次函数调用时部分路径会被覆盖。

【讨论】:

  • 使用第一个不带“+1”的初始化代码返回与手册中要求的值相同的值(我之前已经尝试过)。 SUN_LEN 返回相同的值。虽然感谢四位的回复,但了解 SUN_LEN 以后会更容易。
  • 路径长度为 61 个字符。 sizeof(address.sun_path) 返回 108。我没有动态保留内存,所以我怀疑我正在将任何内容复制到未保留的内存中。
猜你喜欢
  • 2016-06-29
  • 2021-06-24
  • 2015-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多