【问题标题】:Abstract Unix socket between C and GoC 和 Go 之间的抽象 Unix 套接字
【发布时间】:2020-10-13 13:05:15
【问题描述】:

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

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

这是 C 程序:

#include 
#include 
#include 
#include 

/* 接收套接字的缓冲区大小 */
#define BUFFER_SIZE 4096

/* 抽象的 Unix 域套接字地址名称 */
#define UDS_ADDRESS_NAME "#uds-js"

int main() {
    int socket_fd;
    int bytes_received;
    字符缓冲区[BUFFER_SIZE];
    结构 sockaddr_un 服务器地址;
    结构 sockaddr_un 客户端地址;
    socklen_t address_length = sizeof(struct sockaddr_un);

    /* 创建本地 unix 套接字 */
    if ( ( socket_fd = socket (AF_UNIX, SOCK_DGRAM, 0 ) ) 

还有 Go 程序:


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,这确实按预期工作。

EDIT2:

我在 Go 中为抽象套接字创建了一个服务器,在 C 中创建了一个客户端,两个 C 程序和两个 Go 程序可以正常工作。问题似乎出在使用抽象套接字从 C 转到 Go 时。

【问题讨论】:

  • 如果你使套接字不是抽象的(也就是说,它在文件系统上有一个真实的路径),它是否工作?这会将问题分解为两个较小的部分。
  • 也是在启动时删除套接字路径的好习惯:remove(UDS_ADDRESS_NAME),因为如果它已经存在,您将无法使用它。也不知道路径开头的#,这行得通吗?
  • @secretsquirrel,一旦所有对抽象套接字的引用丢失,抽象套接字就会消失;与“经典”UD 套接字相比,这是它们的优势。
  • 哦,是的,你说得对,我以前从未使用过它们
  • 你把server_address.sun_path[0] = '\0';改成/tmp/uds-js时删除了,对吧?

标签: c sockets go unix


【解决方案1】:

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

您的bind() 是针对长度为sizeof(struct sockaddr_un) 的抽象命名空间UNIX 套接字地址生成的。但是,如果我是 reading the Go implementation correctly,则您的 connect() 是针对长度为 9 的套接字地址执行的:sa_family 有两个字节,在这种情况下,len(name) 有七个字节。

这些是不同的套接字。

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

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

【讨论】:

  • 这确实是问题所在。在 C 程序中,我将地址长度更改为 9 并且它起作用了。查看 netstat 输出,名称现在显示为 @uds-js,不再有尾随空值。
  • @dangeroushobo 应该是offsetof(struct sockaddr_un, sun_name[7])
猜你喜欢
  • 2017-10-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-06
相关资源
最近更新 更多