为什么在 Android 中从本机程序连接到 LocalServerSocket 时连接被拒绝

Why Connection refused got when connecting to LocalServerSocket from native program in Android

有一个 java 服务器 LocalServerSocket 监听一个名为 'myaudsocket' 的抽象 unix 域套接字,如:

public void listen() {
    String name = "myaudsocket";
    mSocket = new LocalServerSocket(name);
    LocalSocket client = mSocket.accept();
    ...
}

我可以通过下面的Java代码连接服务器:

public void connect() {
    String name = "myaudsocket";
    LocalSocket client = new LocalSocket();
    client.connect(new LocalSocketAddress(name));
    Log.d("client", "connected to " + name);
}

但是如果我无法通过本机代码连接到服务器:

#define SOKET_NAME "@myaudsocket"
void connect() {
    char* name = SOKET_NAME;
    struct sockaddr_un addr;
    int sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("failed to create socket");
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, SOKET_NAME, sizeof(addr.sun_path)-1);
    if (name[0] == '@') 
       addr.sun_path[0] = '[=13=]';
    
    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("failed to connect");
        close(sock);
        return -1;
    }
    ...
}

控制台总是提示:“连接失败:连接被拒绝”。但是上面的native代码一般是可以工作的 Linux OS (比如Ubuntu).

我该如何解决?

问题出在地址长度上。从官方参考示例https://man7.org/linux/man-pages/man7/unix.7.html,connect()的地址长度参数是sizeof(struct sockaddr_un).

可以在正常的Linux系统(如Ubuntu)下工作。但它不能在 android 中工作。来自 libcutils 的来源:

https://android-opengrok.bangnimang.net/android-9.0.0_r61/xref/system/core/libcutils/socket_local_client_unix.cpp?r=db87e6d1#111

我们可以看到地址长度设置在结束空字符处,不包括填充零。

*alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;

将代码更改为:

#define SOKET_NAME "@myaudsocket"
void connect() {
    char* name = SOKET_NAME;
    struct sockaddr_un addr;

    // add this variant
    int alen;

    int sock = socket(AF_UNIX, SOCK_STREAM, 0);
    if (sock < 0) {
        perror("failed to create socket");
        return -1;
    }

    memset(&addr, 0, sizeof(addr));
    addr.sun_family = AF_UNIX;
    strncpy(addr.sun_path, SOKET_NAME, sizeof(addr.sun_path)-1);
    if (name[0] == '@') 
        addr.sun_path[0] = '[=11=]';

    // Added this line 
    alen = offsetof(struct sockaddr_un, sun_path) + strlen(name);
    
    // change sizeof(addr) to alen
    if (connect(sock, (struct sockaddr *)&addr, alen) < 0) {
        perror("failed to connect");
        close(sock);
        return -1;
    }
}

有效。