为什么在 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 的来源:
我们可以看到地址长度设置在结束空字符处,不包括填充零。
*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;
}
}
有效。
有一个 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 的来源:
我们可以看到地址长度设置在结束空字符处,不包括填充零。
*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;
}
}
有效。