java Android 本地服务器套接字
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/7516018/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android LocalServerSocket
提问by Bohan Lu
In android, there are two classes LocalServerSocket and LocalSocket. I think they are something like AF_LOCAL in unix socket (I am not sure it is correct or not).
在android中,有LocalServerSocket和LocalSocket两个类。我认为它们类似于 unix 套接字中的 AF_LOCAL(我不确定它是否正确)。
My question is that : Is it possible to create LocalServerSocket in Java and use a normal unix socket client to connect to it in native or other process ?
我的问题是:是否可以在 Java 中创建 LocalServerSocket 并使用普通的 unix 套接字客户端在本机或其他进程中连接到它?
If it is possible, what the "sockaddr_un.sun_path" I should set in native ?
如果可能,我应该在 native 中设置什么“sockaddr_un.sun_path”?
I have written a sample project to test it, and I try to set the .sun_path as same as string name used in LocalServerSocket, but it failed, the native could not connect to the Java LocalServerSocket.
我编写了一个示例项目来测试它,我尝试将 .sun_path 设置为与 LocalServerSocket 中使用的字符串名称相同,但它失败了,本机无法连接到 Java LocalServerSocket。
My Java code :
我的Java代码:
package test.socket;
import java.io.IOException;
import java.io.InputStream;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class TestSocketActivity extends Activity {
public static String SOCKET_ADDRESS = "my.local.socket.address";
public String TAG = "Socket_Test";
static{System.loadLibrary("testSocket");}
private native void clientSocketThreadNative();
private native void setStopThreadNative();
localServerSocket mLocalServerSocket;
localClientSocket mLocalClientSocket;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mLocalServerSocket = new localServerSocket();
mLocalClientSocket = new localClientSocket();
}
/* LocalServerSocket */
public class localServerSocket extends Thread {
int bufferSize = 32;
byte[] buffer;
int bytesRead;
int totalBytesRead;
int posOffset;
LocalServerSocket server;
LocalSocket receiver;
InputStream input;
private volatile boolean stopThread;
public localServerSocket() {
Log.d(TAG, " +++ Begin of localServerSocket() +++ ");
buffer = new byte[bufferSize];
bytesRead = 0;
totalBytesRead = 0;
posOffset = 0;
try {
server = new LocalServerSocket(SOCKET_ADDRESS);
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d(TAG, "The LocalServerSocket created failed !!!");
e.printStackTrace();
}
stopThread = false;
}
public void run() {
Log.d(TAG, " +++ Begin of run() +++ ");
while (!stopThread) {
if (null == server){
Log.d(TAG, "The LocalServerSocket is NULL !!!");
stopThread = true;
break;
}
try {
Log.d(TAG, "LocalServerSocket begins to accept()");
receiver = server.accept();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d(TAG, "LocalServerSocket accept() failed !!!");
e.printStackTrace();
continue;
}
try {
input = receiver.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d(TAG, "getInputStream() failed !!!");
e.printStackTrace();
continue;
}
Log.d(TAG, "The client connect to LocalServerSocket");
while (receiver != null) {
try {
bytesRead = input.read(buffer, posOffset,
(bufferSize - totalBytesRead));
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d(TAG, "There is an exception when reading socket");
e.printStackTrace();
break;
}
if (bytesRead >= 0) {
Log.d(TAG, "Receive data from socket, bytesRead = "
+ bytesRead);
posOffset += bytesRead;
totalBytesRead += bytesRead;
}
if (totalBytesRead == bufferSize) {
Log.d(TAG, "The buffer is full !!!");
String str = new String(buffer);
Log.d(TAG, "The context of buffer is : " + str);
bytesRead = 0;
totalBytesRead = 0;
posOffset = 0;
}
}
Log.d(TAG, "The client socket is NULL !!!");
}
Log.d(TAG, "The LocalSocketServer thread is going to stop !!!");
if (receiver != null){
try {
receiver.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (server != null){
try {
server.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void setStopThread(boolean value){
stopThread = value;
Thread.currentThread().interrupt(); // TODO : Check
}
}
/* Client native socket */
public class localClientSocket extends Thread {
private volatile boolean stopThread;
public localClientSocket(){
Log.d(TAG, " +++ Begin of localClientSocket() +++ ");
stopThread = false;
}
public void run(){
Log.d(TAG, " +++ Begin of run() +++ ");
while(!stopThread){
clientSocketThreadNative();
}
}
public void setStopThread(boolean value){
stopThread = value;
setStopThreadNative();
Thread.currentThread().interrupt(); // TODO : Check
}
}
public void bt_startServerOnClick(View v) {
mLocalServerSocket.start();
}
public void bt_startClientOnClick(View v) {
mLocalClientSocket.start();
}
public void bt_stopOnClick(View v) {
mLocalClientSocket.setStopThread(true);
mLocalServerSocket.setStopThread(true);
}
}
My Native code :
我的本机代码:
#define SOCKET_NAME "my.local.socket.address"
JNIEXPORT void JNICALL Java_test_socket_TestSocketActivity_clientSocketThreadNative
(JNIEnv *env, jobject object){
LOGD("In clientSocketThreadNative() : Begin");
stopThread = 1;
int sk, result;
int count = 1;
int err;
char *buffer = malloc(8);
int i;
for(i = 0; i<8; i++){
buffer[i] = (i+1);
}
/*
struct sockaddr_un addr;
bzero((char *)&addr,sizeof(addr);
addr.sun_family = AF_UNIX;
addr.sun_path = SOCKET_NAME;
*/
struct sockaddr_un addr = {
AF_UNIX, SOCKET_NAME
};
LOGD("In clientSocketThreadNative() : Before creating socket");
sk = socket(PF_LOCAL, SOCK_STREAM, 0);
if (sk < 0) {
err = errno;
LOGD("%s: Cannot open socket: %s (%d)\n",
__FUNCTION__, strerror(err), err);
errno = err;
return;
}
LOGD("In clientSocketThreadNative() : Before connecting to Java LocalSocketServer");
if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
err = errno;
LOGD("%s: connect() failed: %s (%d)\n",
__FUNCTION__, strerror(err), err);
close(sk);
errno = err;
return;
}
LOGD("In clientSocketThreadNative() : Connecting to Java LocalSocketServer succeed");
while(!stopThread){
result = write(sk, buffer, 8);
LOGD("In clientSocketThreadNative() : Total write = %d", result);
count++;
if(4 == count){
sleep(1);
count = 0;
}
}
LOGD("In clientSocketThreadNative() : End");
}
Any suggestion would be greatly appreciated !!!
任何建议将不胜感激!!!
回答by Bohan Lu
The following code might not be perfect but it works !!! Thanks for Mike.
以下代码可能不完美,但它有效!!!谢谢迈克。
Java part (Socket Server) :
Java 部分(套接字服务器):
package test.socket;
import java.io.IOException;
import java.io.InputStream;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.content.Intent;
import android.net.LocalServerSocket;
import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
public class TestSocketActivity extends Activity {
public static String SOCKET_ADDRESS = "/test/socket/localServer";
public String TAG = "Socket_Test";
static{System.loadLibrary("testSocket");}
private native void clientSocketThreadNative();
private native void setStopThreadNative();
localSocketServer mLocalSocketServer;
localSocketClient mLocalSocketClient;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mLocalSocketServer = new localSocketServer();
mLocalSocketClient = new localSocketClient();
}
/* LocalSocketServer */
public class localSocketServer extends Thread {
int bufferSize = 32;
byte[] buffer;
int bytesRead;
int totalBytesRead;
int posOffset;
LocalServerSocket server;
LocalSocket receiver;
InputStream input;
private volatile boolean stopThread;
public localSocketServer() {
Log.d(TAG, " +++ Begin of localSocketServer() +++ ");
buffer = new byte[bufferSize];
bytesRead = 0;
totalBytesRead = 0;
posOffset = 0;
try {
server = new LocalServerSocket(SOCKET_ADDRESS);
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d(TAG, "The localSocketServer created failed !!!");
e.printStackTrace();
}
LocalSocketAddress localSocketAddress;
localSocketAddress = server.getLocalSocketAddress();
String str = localSocketAddress.getName();
Log.d(TAG, "The LocalSocketAddress = " + str);
stopThread = false;
}
public void run() {
Log.d(TAG, " +++ Begin of run() +++ ");
while (!stopThread) {
if (null == server){
Log.d(TAG, "The localSocketServer is NULL !!!");
stopThread = true;
break;
}
try {
Log.d(TAG, "localSocketServer begins to accept()");
receiver = server.accept();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d(TAG, "localSocketServer accept() failed !!!");
e.printStackTrace();
continue;
}
try {
input = receiver.getInputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d(TAG, "getInputStream() failed !!!");
e.printStackTrace();
continue;
}
Log.d(TAG, "The client connect to LocalServerSocket");
while (receiver != null) {
try {
bytesRead = input.read(buffer, posOffset,
(bufferSize - totalBytesRead));
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d(TAG, "There is an exception when reading socket");
e.printStackTrace();
break;
}
if (bytesRead >= 0) {
Log.d(TAG, "Receive data from socket, bytesRead = "
+ bytesRead);
posOffset += bytesRead;
totalBytesRead += bytesRead;
}
if (totalBytesRead == bufferSize) {
Log.d(TAG, "The buffer is full !!!");
String str = new String(buffer);
Log.d(TAG, "The context of buffer is : " + str);
bytesRead = 0;
totalBytesRead = 0;
posOffset = 0;
}
}
Log.d(TAG, "The client socket is NULL !!!");
}
Log.d(TAG, "The LocalSocketServer thread is going to stop !!!");
if (receiver != null){
try {
receiver.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (server != null){
try {
server.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void setStopThread(boolean value){
stopThread = value;
Thread.currentThread().interrupt(); // TODO : Check
}
}
/* Client native socket */
public class localSocketClient extends Thread {
private volatile boolean stopThread;
public localSocketClient(){
Log.d(TAG, " +++ Begin of localSocketClient() +++ ");
stopThread = false;
}
public void run(){
Log.d(TAG, " +++ Begin of run() +++ ");
while(!stopThread){
clientSocketThreadNative();
}
}
public void setStopThread(boolean value){
stopThread = value;
setStopThreadNative();
Thread.currentThread().interrupt(); // TODO : Check
}
}
public void bt_startServerOnClick(View v) {
mLocalSocketServer.start();
}
public void bt_startClientOnClick(View v) {
mLocalSocketClient.start();
}
public void bt_stopOnClick(View v) {
mLocalSocketClient.setStopThread(true);
mLocalSocketServer.setStopThread(true);
}
}
Native C part (Client)
本机 C 部分(客户端)
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/un.h>
#include "test_socket_TestSocketActivity.h"
#define LOCAL_SOCKET_SERVER_NAME "/test/socket/localServer"
volatile int stopThread;
#ifndef __JNILOGGER_H_
#define __JNILOGGER_H_
#include <android/log.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef LOG_TAG
#define LOG_TAG "NativeSocket"
#endif
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,LOG_TAG,__VA_ARGS__)
#define LOGS(...) __android_log_print(ANDROID_LOG_SILENT,LOG_TAG,__VA_ARGS__)
#define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
#ifdef __cplusplus
}
#endif
#endif /* __JNILOGGER_H_ */
JNIEXPORT void JNICALL Java_test_socket_TestSocketActivity_clientSocketThreadNative
(JNIEnv *env, jobject object){
LOGD("In clientSocketThreadNative() : Begin");
stopThread = 0;
int sk, result;
int count = 1;
int err;
char *buffer = malloc(8);
int i;
for(i = 0; i<8; i++){
buffer[i] = (i+1);
}
struct sockaddr_un addr;
socklen_t len;
addr.sun_family = AF_LOCAL;
/* use abstract namespace for socket path */
addr.sun_path[0] = 'int socket_make_sockaddr_un(const char *name, int namespaceId,
struct sockaddr_un *p_addr, socklen_t *alen)
{
memset (p_addr, 0, sizeof (*p_addr));
size_t namelen;
switch (namespaceId) {
case ANDROID_SOCKET_NAMESPACE_ABSTRACT:
namelen = strlen(name);
// Test with length +1 for the *initial* '#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <sys/un.h> /* struct sockaddr_un */
#include <stdlib.h> /* for atoi() and exit() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#include <errno.h>
#include <stddef.h>
#define RCVBUFSIZE 2048 /* Size of receive buffer */
void DieWithError(char *errorMessage) /* Error handling function */
{
fprintf(stderr, "Error: %s - %s\n", errorMessage, strerror(errno));
exit(errno);
}
int main(int argc, char *argv[])
{
int sock; /* Socket descriptor */
struct sockaddr_un echoServAddr; /* Echo server address */
unsigned char *localSocketName = "MyTestSocket";
static unsigned char echoString[] = {0x80, 0x00, 0x0e, 0x10, 0x00, 0x9c, 0x40, 0xc9, 0x20, 0x20, 0x20, 0x32, 0x00, 0x00};
static unsigned int echoStringLen = sizeof(echoString); /* Length of string to echo */
unsigned char echoBuffer[RCVBUFSIZE]; /* Buffer for echo string */
int bytesRcvd, totalBytesRcvd; /* Bytes read in single recv()
and total bytes read */
int size;
int i;
/* Create a reliable, stream socket using Local Sockets */
if ((sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
DieWithError("socket() failed");
/* Construct the server address structure */
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
echoServAddr.sun_family = AF_LOCAL; /* Local socket address family */
/**
* Tricky and obscure! For a local socket to be in the "Android name space":
* - The name of the socket must have a 0-byte value as the first character
* - The linux man page is right in that 0 bytes are NOT treated as a null terminator.
* - The man page is not clear in its meaning when it states that "the rest of the bytes in
* sunpath" are used. "Rest of bytes" is determined by the length passed in for
* sockaddr_len and Android sets this per the recommended file-system sockets of
* sizeof(sa_family_t) + strlen(sun_path) + 1. This is important when making calls
* to bind, connect, etc!
* We have initialized the struct sockaddr_un to zero already, so all that is needed is to
* begin the name copy at sun_path[1] and restrict its length to sizeof(echoServAddr.sun_path)-2
**/
strncpy(echoServAddr.sun_path + 1, localSocketName, sizeof(echoServAddr.sun_path) - 2);
size = sizeof(echoServAddr) - sizeof(echoServAddr.sun_path) + strlen(echoServAddr.sun_path+1) + 1;
/* Establish the connection to the echo server */
if (connect(sock, (struct sockaddr *) &echoServAddr, size) < 0)
DieWithError("connect() failed");
/* Send the string to the server */
if (send(sock, echoString, echoStringLen, 0) != echoStringLen)
DieWithError("send() sent a different number of bytes than expected");
/* Receive the same string back from the server */
totalBytesRcvd = 0;
printf("Sent: ");
for (i = 0; i < echoStringLen; i++)
printf("%02X ", echoString[i]);
printf("\n"); /* Print a final linefeed */
printf("Received: "); /* Setup to print the echoed string */
if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0)
DieWithError("recv() failed or connection closed prematurely");
for (i = 0; i < bytesRcvd; i++)
printf("%02X ", echoBuffer[i]);
printf("\n"); /* Print a final linefeed */
close(sock);
exit(0);
}
'.
if ((namelen + 1) > sizeof(p_addr->sun_path)) {
goto error;
}
/*
* Note: The path in this case is *not* supposed to be
* '#include <stdio.h> /* for printf() and fprintf() */
#include <sys/socket.h> /* for socket(), connect(), send(), and recv() */
#include <sys/un.h> /* struct sockaddr_un */
#include <stdlib.h> /* for atoi() and exit() */
#include <string.h> /* for memset() */
#include <unistd.h> /* for close() */
#include <errno.h>
#include <stddef.h>
#define RCVBUFSIZE 2048 /* Size of receive buffer */
void DieWithError(char *errorMessage) /* Error handling function */
{
fprintf(stderr, "Error: %s - %s\n", errorMessage, strerror(errno));
exit(errno);
}
void HandleLocalClient(int clntSocket)
{
char echoBuffer[RCVBUFSIZE]; /* Buffer for echo string */
int recvMsgSize; /* Size of received message */
/* Receive message from client */
if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0)
DieWithError("recv() failed");
/* Send received string and receive again until end of transmission */
while (recvMsgSize > 0) /* zero indicates end of transmission */
{
/* Echo message back to client */
if (send(clntSocket, echoBuffer, recvMsgSize, 0) != recvMsgSize)
DieWithError("send() failed");
/* See if there is more data to receive */
if ((recvMsgSize = recv(clntSocket, echoBuffer, RCVBUFSIZE, 0)) < 0)
DieWithError("recv() failed");
}
close(clntSocket); /* Close client socket */
}
#define MAXPENDING 5 /* Maximum outstanding connection requests */
void DieWithError(char *errorMessage); /* Error handling function */
void HandleLocalClient(int clntSocket); /* TCP client handling function */
int main(int argc, char *argv[])
{
int servSock; /* Socket descriptor for server */
int clntSock; /* Socket descriptor for client */
struct sockaddr_un echoClntAddr; /* Client address */
unsigned int clntLen; /* Length of client address data structure */
struct sockaddr_un echoServAddr; /* Echo server address */
unsigned char *localSocketName = "MyTestSocket";
static unsigned int echoStringLen = 14; /* Length of string to echo */
unsigned char echoBuffer[RCVBUFSIZE]; /* Buffer for echo string */
int bytesRcvd, totalBytesRcvd; /* Bytes read in single recv()
and total bytes read */
int size;
int i;
/* Create a reliable, stream socket using Local Sockets */
if ((servSock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0)
DieWithError("socket() failed");
/* Construct the server address structure */
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
echoServAddr.sun_family = AF_LOCAL; /* Local socket address family */
/**
* Tricky and obscure! For a local socket to be in the "Android name space":
* - The name of the socket must have a 0-byte value as the first character
* - The linux man page is right in that 0 bytes are NOT treated as a null terminator.
* - The man page is not clear in its meaning when it states that "the rest of the bytes in
* sunpath" are used. "Rest of bytes" is determined by the length passed in for
* sockaddr_len and Android sets this per the recommended file-system sockets of
* sizeof(sa_family_t) + strlen(sun_path) + 1. This is important when making calls
* to bind, connect, etc!
* We have initialized the struct sockaddr_un to zero already, so all that is needed is to
* begin the name copy at sun_path[1] and restrict its length to sizeof(echoServAddr.sun_path)-2
**/
strncpy(echoServAddr.sun_path + 1, localSocketName, sizeof(echoServAddr.sun_path) - 2);
size = sizeof(echoServAddr) - sizeof(echoServAddr.sun_path) + strlen(echoServAddr.sun_path+1) + 1;
/* Bind to the local address */
if (bind(servSock, (struct sockaddr *) &echoServAddr, size) < 0)
DieWithError("bind() failed");
/* Mark the socket so it will listen for incoming connections */
if (listen(servSock, MAXPENDING) < 0)
DieWithError("listen() failed");
for (;;) /* Run forever */
{
/* Set the size of the in-out parameter */
clntLen = sizeof(echoClntAddr);
/* Wait for a client to connect */
if ((clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, &clntLen)) < 0)
DieWithError("accept() failed");
/* clntSock is connected to a client! */
printf("Handling client\n");
HandleLocalClient(clntSock);
}
/* NOT REACHED */
return 0;
}
'-terminated. ("man 7 unix" for the gory details.)
*/
p_addr->sun_path[0] = 0;
memcpy(p_addr->sun_path + 1, name, namelen);
...
p_addr->sun_family = AF_LOCAL;
*alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
';
strcpy(&addr.sun_path[1], LOCAL_SOCKET_SERVER_NAME );
len = offsetof(struct sockaddr_un, sun_path) + 1 + strlen(&addr.sun_path[1]);
LOGD("In clientSocketThreadNative() : Before creating socket");
sk = socket(PF_LOCAL, SOCK_STREAM, 0);
if (sk < 0) {
err = errno;
LOGD("%s: Cannot open socket: %s (%d)\n",
__FUNCTION__, strerror(err), err);
errno = err;
return;
}
LOGD("In clientSocketThreadNative() : Before connecting to Java LocalSocketServer");
if (connect(sk, (struct sockaddr *) &addr, len) < 0) {
err = errno;
LOGD("%s: connect() failed: %s (%d)\n",
__FUNCTION__, strerror(err), err);
close(sk);
errno = err;
return;
}
LOGD("In clientSocketThreadNative() : Connecting to Java LocalSocketServer succeed");
while(!stopThread){
result = write(sk, buffer, 8);
LOGD("In clientSocketThreadNative() : Total write = %d", result);
count++;
if(4 == count){
sleep(1);
count = 0;
}
}
LOGD("In clientSocketThreadNative() : End");
}
JNIEXPORT void JNICALL Java_test_socket_TestSocketActivity_setStopThreadNative
(JNIEnv *env, jobject object){
stopThread = 1;
}
回答by mpontillo
Looking at local_socket_client.c
in the Android source, it looks like they do this:
查看local_socket_client.c
Android源代码,看起来他们是这样做的:
It seems like the memset() is important because the entire sun_path
is relevant. (looks like you cover that part with your structure initialization, though.) And it's not "0" plus the original name, it's an actual zero byte! (its value is all binary zeroes, not an ascii '0'
)
看起来 memset() 很重要,因为整个sun_path
都是相关的。(不过,看起来您用结构初始化覆盖了该部分。)而且它不是“0”加上原始名称,而是实际的零字节!(它的值都是二进制零,而不是 ascii '0'
)
Try following more closely what they're doing, including the leading '\0' byte and the AF_LOCAL family.
尝试更密切地关注他们在做什么,包括前导 '\0' 字节和 AF_LOCAL 系列。
If you have updated code (whether it works or not) please post it! I'm interested in your results. Did you ever get this to work?
如果您更新了代码(无论是否有效),请发布!我对你的结果很感兴趣。你有没有让这个工作?
If it doesn't work, find out what errno
is and either call perror()
to print it to stderr
, or call strerror()
and log the output. Let us know what error you get.
如果它不起作用,找出是什么errno
,然后调用perror()
将其打印到stderr
,或者调用strerror()
并记录输出。让我们知道您遇到了什么错误。
Edit
编辑
I recently solved this problem in a project of my own. I found that the key was to specify the correct length when calling connect()
and bind()
. In the code I posted above, it calculates the length by using the offset of the sun_path
in the structure, plus the length of the name, plus one for the leading '\0'
byte. If you specify any other length, Java code might not be able to connect to the socket.
我最近在自己的一个项目中解决了这个问题。我发现关键是在调用connect()
和时指定正确的长度bind()
。在我上面发布的代码中,它通过使用结构中的偏移量sun_path
加上名称的长度,加上前导'\0'
字节的长度来计算长度。如果指定任何其他长度,Java 代码可能无法连接到套接字。
回答by Scott Wagner
Confirmed that the above works properly. The following examples will not only work together, but will work with the corresponding Android LocalSocket and LocalServerSocket classes:
确认以上工作正常。以下示例不仅可以协同工作,还可以与相应的 Android LocalSocket 和 LocalServerSocket 类一起使用:
Client side (Android is server using LocalServerSocket):
客户端(Android 是使用 LocalServerSocket 的服务器):
##代码##Server side (Android is client using LocalSocket):
服务器端(Android 是使用 LocalSocket 的客户端):
##代码##Tested with Android 4.0.3 ICS 03/15
使用 Android 4.0.3 ICS 03/15 测试
回答by thenak
Thanks for the answers here. Piecing people's responses together, the things to be careful about are
感谢这里的答案。将人们的反应拼凑起来,需要注意的是
On the native side:
在原生方面:
- the name of the socket must have a 0-byte value as the first character
- The linux man page is right in that 0 bytes are NOT treated as a null terminator.
- The man page is not clear in its meaning when it states that "the rest of the bytes in sunpath" are used. "Rest of bytes" is determined by the length passed in for
sockaddr_len
and Android sets this per the recommended file-system sockets ofsizeof(sa_family_t) + strlen(sun_path) + 1
. This is important when making calls to bind, connect, etc!
- 套接字的名称必须以 0 字节值作为第一个字符
- linux 手册页是正确的,因为 0 字节不被视为空终止符。
- 当手册页声明“使用 sunpath 中的其余字节”时,其含义不清楚。“其余字节”由传入的长度决定
sockaddr_len
,Android 会根据sizeof(sa_family_t) + strlen(sun_path) + 1
. 这在调用绑定、连接等时很重要!
On the Java side:
在 Java 方面:
Android defines the conventions it uses under the covers but are consistent with above.
Android 定义了它在幕后使用的约定,但与上述约定一致。