跳至主要內容
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?

4563博客

全新的繁體中文 WordPress 網站
  • 首頁
  • 记一次 Android 关于 Unix abstract socket 的连接问题
未分類
9 12 月 2020

记一次 Android 关于 Unix abstract socket 的连接问题

记一次 Android 关于 Unix abstract socket 的连接问题

資深大佬 : howellz 6

Keywords

Android Unix abstract namespace socket LocalSocket LocalServerSocket length 地址长度

正文

在一个项目中,需要 native 的程序对 java 的LocalServerSocket发起连接。即 Java 端监听某个 Unix 套接字,等待 native 的程序连接。结果死活连不上,总是提示Connection Refused(110)。

这是 Java 端的代码示意,非常简单:

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

发现客户端如果用 java 代码连接很容易就连接上了:

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

但是客户端如果使用如下的 c 代码就连接不上:

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

这段代码主要参考权威 man UNIX(7): https://man7.org/linux/man-pages/man7/unix.7.html

注意,这个 SOCKET_NAME 中的第一个字符 @是一个占位符,其实后面被’’取代了,符合abstract unix socket的地址要求。

一直输出:

failed to connect: Connection refused 

同样的代码在普通的 Linux 系统上就可以正常工作,百思不得其姐姐。最后查看LocalSocket的实现代码,发现在 Android 的LocalSocket实现中,使用了如下的代码来确定 address 的长度:

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

这样看来,** 直接传递sizeof(struct sockaddr_un)作为地址长度是不合适的,应该传递的长度不包括结构体中 sun_path[]数组后的全零 padding 。**

修改代码如下:

#define SOKET_NAME "@myname" 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] = '';      // 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;     } } 

再次运行,可以连接上了。

对于 Android 的实现,可以参考如下代码: https://android-opengrok.bangnimang.net/android-9.0.0_r61/xref/system/core/libcutils/socket_local_client_unix.cpp?r=db87e6d1#111

大佬有話說 (1)

  • 資深大佬 : tkl

    分析的可以
    另 百思不得其姐姐?

文章導覽

上一篇文章
下一篇文章

AD

其他操作

  • 登入
  • 訂閱網站內容的資訊提供
  • 訂閱留言的資訊提供
  • WordPress.org 台灣繁體中文

51la

4563博客

全新的繁體中文 WordPress 網站
返回頂端
本站採用 WordPress 建置 | 佈景主題採用 GretaThemes 所設計的 Memory
4563博客
  • Hostloc 空間訪問刷分
  • 售賣場
  • 廣告位
  • 賣站?
在這裡新增小工具