Почему соединение отказалось получать при подключении к LocalServerSocket из родной программы в Android

Существует Java-сервер LocalServerSocket, прослушивающий абстрактный сокет домена unix с именем myaudsocket, например:

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] = '\0';
    
    if (connect(sock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
        perror("failed to connect");
        close(sock);
        return -1;
    }
    ...
}

Консоль всегда говорила: «не удалось подключиться: в соединении отказано». Но приведенный выше собственный код может работать в общей ОС Linux (например, Ubuntu).

Как я могу решить эту проблему?

Почему вы устанавливаете первый байт в NUL? Это последний байт, который должен быть NUL.

user207421 24.12.2020 03:40

@user207421 обратитесь к man7.org/linux/man-pages/man7/unix.7.html, сказано, что «абстрактный: абстрактный адрес сокета отличается (от пути сокета) тем, что sun_path[ 0] является нулевым байтом ('\0')."

progquester 24.12.2020 03:51
0
2
1 087
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в длине адреса. Из официального справочного примера https://man7.org/linux/man-pages/man7/unix.7.html параметр длины адреса для connect() равен sizeof(struct sockaddr_un).

Он может работать в обычной системе Linux (например, Ubuntu). Но он не может работать в андроиде. Из источника 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] = '\0';

    // 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;
    }
}

Оно работает.

Другие вопросы по теме