我最近通过localsocket写了一个框架和应用程序之间的通信示例,本机服务器套接字代码:
#include "base.h"
#include "util.h"
namespace yanghui{
JavaVM* getJavaVm();
Constants* getConstants();
};
using namespace yanghui;
namespace localsocket{
#define MAX_BUFFER_SIZE 80
/**
* create a local unix socket.
*/
int NewLocalSocket(JNIEnv* env,jobject obj){
LOGD("Constructing a new Local UNIX socket...");
int localSocket = socket(PF_LOCAL,SOCK_STREAM,0);
if( -1 == localSocket){
getConstants()->throwJavaException(env,"java/io/IOException",errno);
}
return localSocket;
}
/**
* binding socket.
*/
void BindLocalSocketToName(JNIEnv* env,jobject obj,int sd,const char* name){
struct sockaddr_un address;
const size_t nameLength = strlen(name);
size_t pathLength = nameLength;
bool abstractNamespace = ('/' != name[0]);
if(abstractNamespace){
pathLength++;
}
if(pathLength > sizeof(address.sun_path)){
getConstants()->throwJavaException(env,"java/io/IOException",errno);
}else{
memset(&address,0,sizeof(address));
address.sun_family = PF_LOCAL;
char* sunPath = address.sun_path;
//If namespace is abstract,the first byte is 0.
if(abstractNamespace){
*sunPath++ = NULL;
}
//append name.
strcpy(sunPath,name);
//Address length.
socklen_t addressLength = (offsetof(struct sockaddr_un,sun_path))
+ pathLength;
unlink(address.sun_path);
LOGD("Binding to local name %s%s.",(abstractNamespace)?"null":"",name);
bind(sd,(struct sockaddr*)&address,addressLength);
/*
if(-1 == bind(sd,(struct sockaddr*)&address,addressLength)){
getConstants()->throwJavaException(env,"java/io/IOException","Binding socket error ~");
}
*/
}
}
/**
* waiting for socket.
*/
int AcceptOnLocalSocket(JNIEnv* env,jobject obj,int sd){
LOGD("Waiting for a client connection...");
int clientSocket = accept(sd,NULL,NULL);
LOGD("sd = %d ",sd);
if(-1 == clientSocket){
getConstants()->throwJavaException(env,"java/io/IOException",errno);
}
return clientSocket;
}
/**
* Listening coming in socketclient.
*/
void ListenOnSocket(JNIEnv* env,jobject obj,int sd,int backlog){
LOGD("Listening on socket with a backlog of %d pending connections.",backlog);
listen(sd,backlog);
/*
if( -1 == listen(sd,backlog)){
getConstants()->throwJavaException(env,"java/io/IOException",errno);
}
*/
}
/**
* Receive buffer from localsocket.
*/
ssize_t ReceiveFromSocket(JNIEnv* env,jobject obj,int sd,char* buffer,size_t bufferSize){
LOGD("Receiving from the socket...");
ssize_t recvSize = recv(sd,buffer,bufferSize-1,0);
if(-1 == recvSize){
getConstants()->throwJavaException(env,"java/io/IOException",errno);
}else{
buffer[recvSize] = NULL;
if(recvSize > 0){
LOGD("Received %d bytes : %s",recvSize,buffer);
}else{
LOGD("Client disconnected.");
}
}
return recvSize;
}
/**
* send buffer to socket.
*/
ssize_t SendToSocket(JNIEnv* env,jobject obj,int sd,const char* buffer,size_t bufferSize){
LOGD("Sending to the socket...");
ssize_t sentSize = send(sd,buffer,bufferSize,0);
if(-1 == sentSize){
getConstants()->throwJavaException(env,"java/io/IOException",errno);
}else{
if(sentSize > 0){
LOGD("Sent %d bytes : %s",sentSize,buffer);
}else{
LOGD("Client disconnected.");
}
}
return sentSize;
}
/**
* start Localsocket server
*/
void com_jni_nativeStartLocalServer(JNIEnv* env,jobject obj,jstring name){
int serverSocket = NewLocalSocket(env,obj);
if(NULL == env->ExceptionOccurred()){
const char* nameText = env->GetStringUTFChars(name,NULL);
if(NULL == nameText)
goto exit;
BindLocalSocketToName(env,obj,serverSocket,nameText);
env->ReleaseStringUTFChars(name,nameText);
if(NULL != env->ExceptionOccurred()){
LOGD("binding error");
goto exit;
}
ListenOnSocket(env,obj,serverSocket,4);
if(NULL != env->ExceptionOccurred()){
LOGD("listen error");
goto exit;
}
int clientSocket = AcceptOnLocalSocket(env,obj,serverSocket);
if(NULL != env->ExceptionOccurred()){
LOGD("acceptOnLocalSocket error.");
goto exit;
}
char buffer[MAX_BUFFER_SIZE];
ssize_t recvSize;
ssize_t sentSize;
while(1){
recvSize = ReceiveFromSocket(env,obj,clientSocket,buffer,MAX_BUFFER_SIZE);
if((0 == recvSize) || (NULL != env->ExceptionOccurred()))
break;
sentSize = SendToSocket(env,obj,clientSocket,buffer,(size_t)recvSize);
if((0 == sentSize) || (NULL != env->ExceptionOccurred()))
break;
}
close(clientSocket);
}
exit:
if(serverSocket > 0){
close(serverSocket);
}
}
};
客户端套接字:
/**
* filp local socket commuication activity
* @param view
*/
public void LocalSocket(View view){
final String socketName = "/data/data/com.example.administrator.helloworld/files/file";
final String message = "test";
ServerTask serverTask = new ServerTask(socketName);
serverTask.start();
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
ClientTask clientTask = new ClientTask(socketName,message);
clientTask.start();
}
},3000);
}
/**
* Server Task
*/
private class ServerTask extends Thread{
private final String serverName;
public ServerTask(String name){
serverName = name;
}
@Override
public void run() {
Log.d("ServerTask","Starting server .");
try{
ndktest.nativeStartLocalServer(serverName);
}catch (Exception e){
e.printStackTrace();
}
}
}
//Client Task
private class ClientTask extends Thread{
private final String name;
private final String message;
public ClientTask(String name,String message){
this.name = name;
this.message = message;
}
@Override
public void run() {
Log.d("ClientTask","Starting client");
try{
startLocalClient(name,message);
}catch (Exception e){
e.printStackTrace();
}
}
}
private void startLocalClient(String name,String message) throws Exception{
//create a localsocket
LocalSocket clientSocket = new LocalSocket();
try{
//setting localsocket namespace
LocalSocketAddress.Namespace namespace = LocalSocketAddress.Namespace.FILESYSTEM;;
LocalSocketAddress address = new LocalSocketAddress(name,namespace);
Log.i("startLocalClient","Connecting to "+name);
clientSocket.connect(address);
Log.i("startLocalClient","Connected.");
byte[] messageBytes = message.getBytes();
Log.i("startLocalClient","Sending to the socket...");
OutputStream outputStream = clientSocket.getOutputStream();
outputStream.write(messageBytes);
Log.i("startLocalClient",String.format("Sent %d bytes : %s",messageBytes.length,message));
Log.i("startLocalClient","Receiving from the socket...");
InputStream inputStream = clientSocket.getInputStream();
int readSize = inputStream.read(messageBytes);
String receivedMessage = new String(messageBytes,0,readSize);
Log.i("startLocalClient",String.format("Received %d bytes: %s",readSize,receivedMessage));
outputStream.close();
inputStream.close();
}catch (Exception e){
e.printStackTrace();
}finally {
clientSocket.close();
}
}
我使用FILESYSTEM创建localsocket,但运行logcat是:
01-01 08:24:48.504 14396-14836/com.example.administrator.helloworld D/ServerTask: Starting server .
01-01 08:24:48.505 14396-14836/com.example.administrator.helloworld D/ndklog: Constructing a new Local UNIX socket...
01-01 08:24:48.505 14396-14836/com.example.administrator.helloworld D/ndklog: Binding to local name /data/data/com.example.administrator.helloworld/files/file.
01-01 08:24:48.505 14396-14836/com.example.administrator.helloworld D/ndklog: Listening on socket with a backlog of 4 pending connections.
01-01 08:24:48.505 14396-14836/com.example.administrator.helloworld D/ndklog: Waiting for a client connection...
01-01 08:24:48.505 14396-14836/com.example.administrator.helloworld D/ndklog: sd = 42
01-01 08:24:48.507 14396-14836/com.example.administrator.helloworld D/ndklog: acceptOnLocalSocket error.
01-01 08:24:48.507 14396-14836/com.example.administrator.helloworld W/System.err: java.io.IOException: Invalid argument
01-01 08:24:48.507 14396-14836/com.example.administrator.helloworld W/System.err: at com.example.administrator.helloworld.Ndktest.nativeStartLocalServer(Native Method)
01-01 08:24:48.507 14396-14836/com.example.administrator.helloworld W/System.err: at com.example.administrator.helloworld.MainActivity$ServerTask.run(MainActivity.java:77)
01-01 08:24:51.510 14396-14938/com.example.administrator.helloworld D/ClientTask: Starting client
01-01 08:24:51.511 14396-14938/com.example.administrator.helloworld I/startLocalClient: Connecting to /data/data/com.example.administrator.helloworld/files/file
01-01 08:24:51.512 14396-14938/com.example.administrator.helloworld W/System.err: java.io.IOException: No such file or directory
01-01 08:24:51.512 14396-14938/com.example.administrator.helloworld W/System.err: at android.net.LocalSocketImpl.connectLocal(Native Method)
01-01 08:24:51.512 14396-14938/com.example.administrator.helloworld W/System.err: at android.net.LocalSocketImpl.connect(LocalSocketImpl.java:290)
01-01 08:24:51.512 14396-14938/com.example.administrator.helloworld W/System.err: at android.net.LocalSocket.connect(LocalSocket.java:130)
01-01 08:24:51.512 14396-14938/com.example.administrator.helloworld W/System.err: at com.example.administrator.helloworld.MainActivity.startLocalClient(MainActivity.java:118)
01-01 08:24:51.512 14396-14938/com.example.administrator.helloworld W/System.err: at com.example.administrator.helloworld.MainActivity.access$000(MainActivity.java:13)
01-01 08:24:51.512 14396-14938/com.example.administrator.helloworld W/System.err: at com.example.administrator.helloworld.MainActivity$ClientTask.run(MainActivity.java:99)
我在触摸文件下的/data/data/com./files目录中使用ADB shell,然后运行,结果是:
01-01 08:30:28.472 14396-26420/com.example.administrator.helloworld D/ServerTask: Starting server .
01-01 08:30:28.472 14396-26420/com.example.administrator.helloworld D/ndklog: Constructing a new Local UNIX socket...
01-01 08:30:28.473 14396-26420/com.example.administrator.helloworld D/ndklog: Binding to local name /data/data/com.example.administrator.helloworld/files/file.
01-01 08:30:28.474 14396-26420/com.example.administrator.helloworld D/ndklog: Listening on socket with a backlog of 4 pending connections.
01-01 08:30:28.474 14396-26420/com.example.administrator.helloworld D/ndklog: Waiting for a client connection...
01-01 08:30:28.474 14396-26420/com.example.administrator.helloworld D/ndklog: sd = 41
01-01 08:30:28.475 14396-26420/com.example.administrator.helloworld D/ndklog: acceptOnLocalSocket error.
01-01 08:30:28.475 14396-26420/com.example.administrator.helloworld W/System.err: java.io.IOException: Invalid argument
01-01 08:30:28.475 14396-26420/com.example.administrator.helloworld W/System.err: at com.example.administrator.helloworld.Ndktest.nativeStartLocalServer(Native Method)
01-01 08:30:28.475 14396-26420/com.example.administrator.helloworld W/System.err: at com.example.administrator.helloworld.MainActivity$ServerTask.run(MainActivity.java:77)
01-01 08:30:31.465 14396-26525/com.example.administrator.helloworld D/ClientTask: Starting client
01-01 08:30:31.465 14396-26525/com.example.administrator.helloworld I/startLocalClient: Connecting to /data/data/com.example.administrator.helloworld/files/file
01-01 08:30:31.466 14396-26525/com.example.administrator.helloworld W/System.err: java.io.IOException: Connection refused
01-01 08:30:31.466 14396-26525/com.example.administrator.helloworld W/System.err: at android.net.LocalSocketImpl.connectLocal(Native Method)
01-01 08:30:31.466 14396-26525/com.example.administrator.helloworld W/System.err: at android.net.LocalSocketImpl.connect(LocalSocketImpl.java:290)
01-01 08:30:31.467 14396-26525/com.example.administrator.helloworld W/System.err: at android.net.LocalSocket.connect(LocalSocket.java:130)
01-01 08:30:31.467 14396-26525/com.example.administrator.helloworld W/System.err: at com.example.administrator.helloworld.MainActivity.startLocalClient(MainActivity.java:118)
01-01 08:30:31.467 14396-26525/com.example.administrator.helloworld W/System.err: at com.example.administrator.helloworld.MainActivity.access$000(MainActivity.java:13)
01-01 08:30:31.467 14396-26525/com.example.administrator.helloworld W/System.err: at com.example.administrator.helloworld.MainActivity$ClientTask.run(MainActivity.java:99)
我在公司使用相同代码进行通信,公司Android源码是4.4,我在家里用Android源代码6,谷歌是一个限制,我希望他们正常通信,我该如何解决它吗