Unix域:connect():没有这样的文件或目录

Unix Domain : connect() : No such file or directory

本文关键字:文件 connect Unix      更新时间:2023-10-16

如标题所述,我对具有相应地址的unix域类型套接字的connect()调用导致错误ENOENT:没有这样的文件或目录

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

这是我的连接()尝试:

struct sockaddr_un address;
address.sun_family = AF_UNIX;
memcpy(address.sun_path, filepath.c_str(), filepath.length());
address.sun_path[filepath.length()] = '';
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:无效参数错误,并且我得到了ENOENT:没有这样的文件或目录,只有最后一个。我甚至尝试了互联网上的全部例子,但都没有成功。显然,用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.net或www.kernel.org上更新。如果相关的话,我的操作系统是Debian Squeeze。

你知道我做错了什么吗?如何解决?如果你需要更多的代码或有问题,请毫不犹豫地问我(尽管我可能不需要说明,但这是我在这里的第一篇文章>.<)

btw,很抱歉我的英语不好

更新2

已解决。为了清楚起见,我将把它放在下面的一个额外的答案中。

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

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

有人知道为什么我需要将整个变量设置为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部分。这与手册中的警告相匹配,即使用"而不是分配大小!"正如你的帖子所说,如果没有+ 1,这也不起作用,但可能性很小。

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