Android LocalServerSocket
В android существуют два класса LocalServerSocket и LocalSocket. Я думаю, что они что-то вроде AF_LOCAL в unix-сокете (я не уверен, что это правильно или нет).
Мой вопрос в том, что:
Возможно ли создать LocalServerSocket на Java и использовать обычный клиент сокета unix для подключения к нему в собственном или другом процессе?
Если это возможно, то что "sockaddr_un.sun_path" я должен установить в native?
Я написал образец проекта для его проверки, и я пытаюсь установить .sun_path так же, как имя строки, используемое в LocalServerSocket, но это не удалось, родной не удалось подключиться к Java LocalServerSocket.
Мой код 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);
}
}
Мой основной код:
#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");
}
Любое предложение будет принята с благодарностью!
Ответы
Ответ 1
Следующий код может быть не идеальным, но он работает!!! Спасибо, Майк.
Часть Java (Socket Server):
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 (Клиент)
#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] = '\0';
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;
}
Ответ 2
Глядя на local_socket_client.c
в Android-устройство, похоже, что они делают это:
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* '\0'.
if ((namelen + 1) > sizeof(p_addr->sun_path)) {
goto error;
}
/*
* Note: The path in this case is *not* supposed to be
* '\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;
Похоже, memset() важен, потому что весь sun_path
имеет значение. (похоже, вы закрываете эту часть своей инициализацией своей структуры.) И это не "0" плюс оригинальное имя, это фактический нулевой байт! (его значением являются все бинарные нули, а не ascii '0'
)
Постарайтесь более внимательно следить за тем, что они делают, включая ведущий '\ 0' байт и семейство AF_LOCAL.
Если у вас есть обновленный код (независимо от того, работает он или нет), отправьте его! Меня интересуют ваши результаты. Вы когда-нибудь заставляли это работать?
Если это не сработает, узнайте, что такое errno
, и либо вызывайте perror()
, чтобы напечатать его на stderr
, либо вызовите strerror()
и запишите выход. Сообщите нам, какую ошибку вы получите.
Edit
Недавно я решил эту проблему в собственном проекте. Я обнаружил, что ключ должен был указать правильную длину при вызове connect()
и bind()
. В вышеприведенном коде он вычисляет длину, используя смещение sun_path
в структуре, плюс длину имени, плюс один для ведущего байта '\0'
. Если вы укажете какую-либо другую длину, код Java не сможет подключиться к сокету.
Ответ 3
Подтверждено, что приведенное выше работает правильно. Следующие примеры будут не только работать вместе, но и работать с соответствующими классами Android LocalSocket и LocalServerSocket:
Клиентская сторона (Android - сервер, использующий LocalServerSocket):
#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);
}
Серверная сторона (Android - клиент, использующий LocalSocket):
#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;
}
Протестировано с Android 4.0.3 ICS 03/15
Ответ 4
Спасибо за ответы здесь. Собирая ответы людей вместе, вещи, о которых нужно быть осторожными, - это
На внутренней стороне:
- имя сокета должно иметь 0-байтовое значение в качестве первого символа
- Линейная страница linux права в том, что 0 байтов НЕ обрабатываются как нулевой терминатор.
- Страница руководства не понятна по своему значению, когда она заявляет, что используются "остальные байты в пути солнца". "Остальная часть байтов" определяется длиной, переданной для
sockaddr_len
, и Android устанавливает это для рекомендуемых сокетов файловой системы sizeof(sa_family_t) + strlen(sun_path) + 1
. Это важно при вызове bind, connect и т.д.
На стороне Java:
Android определяет соглашения, которые он использует под обложками, но согласуется с выше.