8

如标题中所述,我对具有相应地址的 unix 域类型套接字的connect()调用导致错误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);

令人惊讶的是,除了最后一个之外的所有初始化都会导致EINVAL: connect()的参数无效错误,我得到ENOENT: no such file or directory只有最后一个。我什至从互联网上尝试了整个示例,但没有成功。显然,用 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

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

4

2 回答 2

2

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

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

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

于 2012-07-25T10:55:38.067 回答
0

引用glibc 手册

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

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

下面的示例使用您说它失败的计算:

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

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

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

于 2012-07-24T13:27:59.067 回答