c - C 和 Go 之间的抽象 Unix 套接字

标签 c sockets go unix

我正在使用抽象 Unix 套接字在 C 和 Go 程序之间传递数据。 C 程序正在创建套接字,Go 程序连接到它。问题是 Go 程序无法连接到套接字,我收到以下错误消息:

UDS connection failed: dial unixgram @uds-js: connect: connection refused

这是 C 程序:

#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

/* Buffer size for the receive socket */
#define BUFFER_SIZE 4096

/* The abstract Unix domain socket address name */
#define UDS_ADDRESS_NAME "#uds-js"

int main() {
    int socket_fd;
    int bytes_received;
    char buffer[BUFFER_SIZE];
    struct sockaddr_un server_address;
    struct sockaddr_un client_address;
    socklen_t address_length = sizeof(struct sockaddr_un);

    /* Create local unix socket */
    if ( ( socket_fd = socket ( AF_UNIX, SOCK_DGRAM, 0 ) ) < 0 ) {
        printf ( "socket error\n" );
        return 1;
    }

    /* Set an abstract socket address */
    memset( &server_address, 0, sizeof(server_address) );
    server_address.sun_family = AF_UNIX;
    strcpy( server_address.sun_path, UDS_ADDRESS_NAME );
    server_address.sun_path[0] = '\0';

    /* Bind socket to address */
    if ( bind ( socket_fd, (const struct sockaddr *) &server_address, address_length ) < 0 ) {
        close ( socket_fd );
        printf ( "socket bind error\n" );
        return 1;
    }
    bytes_received =
            recvfrom(
                socket_fd,
                &buffer,
                BUFFER_SIZE,
                0,
                (struct sockaddr *) &client_address,
                &address_length );
    printf ( "Received: %s\n", buffer );
    return 0;
}

And the Go program:


import (
    "fmt"
    "net"
    "os"
)

func main() {
    addr, _ := net.ResolveUnixAddr("unixgram", "@uds-js")
    udsSock, err := net.DialUnix("unixgram", nil, addr)
    if err != nil {
        fmt.Printf("UDS connection failed: %v\n", err)
        os.Exit(1)
    }
    defer udsSock.Close()
    if _, err := udsSock.Write([]byte("{\"test\":100}")); err != nil {
        fmt.Printf("Failed to send message on UDS: %v\n", err)
    }
}

在 C 程序中,我将套接字名称中的第一个字节设置为空字节,as to spec 。根据我收集的信息in Go该名称需要以 @ 开头。

运行netstat我可以看到套接字已创建:

$ netstat -ax | grep DGRAM
unix  2      [ ]         DGRAM                    12411992 @uds-js@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

为什么Go程序连接socket失败?

编辑:

将名称更改为路径名 /tmp/uds-js,这确实可以按预期工作。

编辑2:

我用 Go 语言创建了一个服务器,用 C 语言为抽象套接字创建了一个客户端,这两个 C 程序和两个 Go 程序可以很好地协同工作。问题似乎出在使用抽象套接字从 C 转到 Go 时。

最佳答案

Go 程序连接到错误的抽象套接字(或者,等效地,C 程序绑定(bind)到错误的抽象套接字)。

您的bind()是针对长度为sizeof(struct sockaddr_un)的抽象命名空间UNIX套接字地址进行的。如果我是reading the Go implementation correctly但是,您的 connect() 是针对长度为 9 的套接字地址执行的:sa_family 为两个字节,在本例中为 len(名称)

这些是不同的套接字。

在抽象命名空间中,NULL 并不特殊,因此 "\0uds-js" 是一个有效的套接字地址,而 "\0uds-js\0\0\0\0\0\0\0\0..." 是一个不同的有效地址。

strace 两个进程都会查看 C 程序的 bind() 和 Go 程序的 connect()。我希望您会看到它们使用不同的 socklen_t 参数调用这些函数。

关于c - C 和 Go 之间的抽象 Unix 套接字,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62535276/

相关文章:

c - 使用 cmake 编译时 Valgrind 不显示行号

c - sizeof(arr+1) 输出错误?

c++ - 超过 1024 个客户端使用 fd_set?

c - 额外的变量导致段错误

c - 这是 C 语言未定义的行为吗? clang 和 GCC 的不同结果

c++ - 为什么 Go 套接字比 C++ 套接字慢?

Android客户端使用Socket发送大文件,服务器收到的文件不完整

go - 从 net.UDPConn 读取会锁定 PC

go - 如何在 Go 中存储 ECDSA 私钥

go - golang中的var()是什么意思