IPC QLocalSocket -> C,为啥我的连接失败?连接失败:[2](没有这样的文件?!)

Posted

技术标签:

【中文标题】IPC QLocalSocket -> C,为啥我的连接失败?连接失败:[2](没有这样的文件?!)【英文标题】:IPC QLocalSocket -> C, why is my connect failing ? connect failed: [2] (no such file?!)IPC QLocalSocket -> C,为什么我的连接失败?连接失败:[2](没有这样的文件?!) 【发布时间】:2015-10-20 09:15:53 【问题描述】:

我正在运行这个示例http://doc.qt.io/qt-5/qtcore-ipc-localfortuneserver-example.html

使用cat <socket_name> 工作正常,我什至设法连接到python。

但是不幸的是,这失败了。 -> connect() 失败:[2][没有这样的文件或目录]? W H Y ¿

#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>

#define SOCK_PATH "/Users/Name/socket"

int main(void) 
    int sockfd = 0,n = 0, err = 0;
    char recvBuff[1024];
    struct sockaddr_un serv_addr;
    const char* const pcSocketName = SOCK_PATH;
    memset(recvBuff, '0' ,sizeof(recvBuff));
    if((sockfd = socket(AF_UNIX, SOCK_STREAM, 0))< 0) 
        printf("\n Error : Could not create socket \n");
        return 1;
    
    serv_addr.sun_family = AF_UNIX;
    serv_addr.sun_path[0] = '\0';
    strncpy(serv_addr.sun_path+1, pcSocketName, strlen(pcSocketName));
    err = connect(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr));
    if(0 != err) 
        printf("connect() failed: [%d][%s]\n", errno, strerror(errno));
        return(-1);
    
    while((n = read(sockfd, recvBuff, sizeof(recvBuff)-1)) > 0) 
        recvBuff[n] = 0;
        if(fputs(recvBuff, stdout) == EOF) 
            printf("\n Error : Fputs error");
        
        printf("\n");
    
    if( n < 0) 
        printf("\n Read Error \n");
    
    printf("Over..\n");
    return 0;

我在 MacOS 上运行,使用 gcc 构建。这段代码的一部分来自网络上的不同地方。

【问题讨论】:

【参考方案1】:

socket路径复制行错误:

strncpy(serv_addr.sun_path+1, pcSocketName, strlen(pcSocketName));

您想将pcSocketName 复制到serv_addr.sun。此外,保护strlen(pcSocketName) 在这里没有任何意义。你可以只使用

strcpy(serv_addr.sun_path, pcSocketName);

在简单的例子中,strcpy 是安全的,如果我们确定SOCK_PATH 的长度足够小以适合缓冲区serv_addr.sun_path。但是,为了避免意外错误或在字符串长度可能变化的更复杂的情况下,防止潜在的溢出是有意义的。函数strncpy 可用于从pcSocketName 复制不超过sizeof(serv_addr.sun_path) - 1 字节。一个字节是为零终止字符保留的。如果在strncpy 中达到长度限制,则不会附加最后一个空字符。所以,应该手动设置:

serv_addr.sun_path[sizeof(serv_addr.sun_path) - 1] = '\0';
strncpy(serv_addr.sun_path, pcSocketName, sizeof(serv_addr.sun_path) - 1);

我猜你的代码是基于Can not connect to Linux "abstract" unix socket

这导致了最初的连接问题。 sun_path[] 中的第一个字节应该为零 (serv_addr.sun_path[0] = '\0';) 才能使用 抽象命名空间 UNIX 套接字。然而,这样的抽象命名空间是一个不可移植的 Linux 扩展:

Mac OS X(和 OS X)不支持抽象命名空间套接字 Qt QLocalSocket 即使在 Linux 上也不支持它:QTBUG-16090

所以,QLocalSocket 与文件系统套接字一起工作。在 C 中,此类套接字应仅通过 sun_path 中的以 null 结尾的文件系统路径名来访问。

【讨论】:

关于保护,我认为一种或另一种就足够了,但两者都是多余的吗? @thomas 是的,您可以使用strcpy(您的路径长度足够小,您可以手动设置)或者确保路径适合serv_addr.sun_path,您可以使用strncpy并手动设置最后一个零字节。顺便说一句,为了澄清连接问题,我猜您的代码来自关于abstract 套接字***.com/questions/11640826/… 的帖子您会发现抽象套接字不使用真实文件名,但您有可以与cat 一起使用的真实文件。

以上是关于IPC QLocalSocket -> C,为啥我的连接失败?连接失败:[2](没有这样的文件?!)的主要内容,如果未能解决你的问题,请参考以下文章

qt浏览器插件中的IPC

Qt基础之二十:进程间通信

Qt基础之二十:进程间通信

C程序IPC消息

IPC之sem.c源码解读

快速 java/python/C++ ipc