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

时间:2012-07-24 13:09:30

标签: c++ unix-socket

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

正确初始化两个套接字,并相应地创建和绑定套接字文件。服务器和客户端套接字在不同的进程中运行,但客户端进程是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:无效参数错误,我得到 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(地址)返回110,因为它应该是

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

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

顺便说一句,抱歉我的英文不好

更新2

解决。我将在下面的额外答案中将其发布为清晰度。

2 个答案:

答案 0 :(得分:2)

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

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

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

答案 1 :(得分:0)

引用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部分。这与手册中的警告相匹配,使用“分配大小!”正如您的帖子所说,如果没有+ 1这也不起作用,可能会很渺茫。

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