转:Android应用与framework的socket通信实例
https://blog.****.net/goleftgoright/article/details/7406292
关于Android应用与Framework的socket通信,相信关心这个问题的朋友们已经看过《android使用socket使底层和framework通信》这篇文章,美中不足的是作者只贴出一些关键的代码片段而并没有放出源码。我这里还是以一个能实际运行的例子为基础来讲,这样也方便大家学习。
首先看一下效果,如下图。我填写姓名"Potter",选择性别"Mr"然后点击发送,底层socket收到消息后将消息直接返回给我,我将返回的结果(Mr.Potter)直接显示在Result。
ok,有了初步了解后我们现在来看一下如何一步步实现这个例子。
1、配置init.rc。我在init.rc加入如下配置
- service htfskservice /system/bin/htfsk
- socket htfsk stream 666 system system
- oneshot
这里配置了一个名为 “htfskservice” 的服务,手机开机后该服务会自启动并运行/system/bin目录下的脚本htfsk(步骤二将提到如何生成这个脚本)。
同时这里还配置了一个名为 "htfsk" 的socket,并且只有拥有system权限的应用才允许连接这个socket,如何使应用获取system权限可以参考http://my.unix-center.net/~Simon_fu/?p=531这篇文章。
2、编写socket服务端代码,生成可执行脚本htfsk。
首先来看下socket服务端代码 htfsk.c ,内容如下:
- #define SOCKET_NAME "htfsk"
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <sys/wait.h>
- #include <sys/un.h>
- #include <cutils/sockets.h>
- #include <utils/Log.h>
- #include <android/log.h>
- int main(){
- char log[200];
- int connect_number = 6;
- int fdListen = -1, new_fd = -1;
- int ret;
- struct sockaddr_un peeraddr;
- socklen_t socklen = sizeof (peeraddr);
- int numbytes ;
- char buff[256];
- //这一步很关键,就是获取init.rc中配置的名为 "htfsk" 的socket
- fdListen = android_get_control_socket(SOCKET_NAME);
- if (fdListen < 0) {
- sprintf(log,"Failed to get socket '" SOCKET_NAME "' errno:%d", errno);
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log);
- exit(-1);
- }
- //开始监听
- ret = listen(fdListen, connect_number);
- sprintf(log,"Listen result %d",ret);
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log);
- if (ret < 0) {
- perror("listen");
- exit(-1);
- }
- //等待Socket客户端发启连接请求
- new_fd = accept(fdListen, (struct sockaddr *) &peeraddr, &socklen);
- sprintf(log,"Accept_fd %d",new_fd);
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log);
- if (new_fd < 0 ) {
- sprintf(log,"%d",errno);
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log);
- perror("accept error");
- exit(-1);
- }
- while(1){
- //循环等待Socket客户端发来消息
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI","Waiting for receive");
- if((numbytes = recv(new_fd,buff,sizeof(buff),0))==-1){
- sprintf(log,"%d",errno);
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log);
- perror("recv");
- continue;
- }
- //发送消息回执给Socket客户端
- if(send(new_fd,buff,strlen(buff),0)==-1)
- {
- perror("send");
- close(new_fd);
- exit(0);
- }
- }
- close(new_fd);
- close(fdListen);
- return 0;
- }
写好服务端代码后我们要将他编译成可执行脚本htfsk,编译的Android.mk内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS :=optional
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_MODULE:= htfsk
LOCAL_SRC_FILES:=htfsk.c
LOCAL_PRELINK_MODULE := false
include $(BUILD_EXECUTABLE)
编译成功后就会在/system/bin/目录下找到生成的可执行脚本htfsk
3、编写客户端java代码。核心代码如下:
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import android.net.LocalSocket;
- import android.net.LocalSocketAddress;
- import android.util.Log;
- /**
- * Socket客户端
- *
- * @author lai_zs
- * @date:2012-3-17 下午12:15:09
- */
- public class SocketClient {
- private final String SOCKET_NAME = "htfsk";
- private LocalSocket client;
- private LocalSocketAddress address;
- private boolean isConnected = false;
- private int connetTime = 1;
- public SocketClient() {
- client = new LocalSocket();
- address = new LocalSocketAddress(SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);
- new ConnectSocketThread().start();
- }
- /**
- * 发送消息
- * @param msg
- * @return 返回Socket服务端的消息回执
- */
- public String sendMsg(String msg) {
- if (!isConnected) {
- return "Connect fail";
- }
- try {
- BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
- PrintWriter out = new PrintWriter(client.getOutputStream());
- out.println(msg);
- out.flush();
- return in.readLine();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return "Nothing return";
- }
- /**
- * 异步连接Socket,如果连接不上会尝试重复连接十次
- *
- * @author Administrator
- *
- */
- private class ConnectSocketThread extends Thread {
- @Override
- public void run() {
- while (!isConnected && connetTime <= 10) {
- try {
- sleep(1000);
- Log.i("SocketClient","Try to connect socket;ConnectTime:"+connetTime);
- client.connect(address);
- isConnected = true;
- } catch (Exception e) {
- connetTime++;
- isConnected = false;
- Log.i("SocketClient","Connect fail");
- }
- }
- }
- }
- /**
- * 关闭Socket
- */
- public void closeSocket() {
- try {
- client.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
总结:经过以上三个步骤本实例就基本完成了,源码工程MySocket我已经上传至http://download.****.net/detail/goleftgoright/4183596
工程MySocket使用步骤:
1、配置init.rc。
2、将工程MySocket拷贝到android源码的/packages/apps目录下编译就可以了。
编译成功后就可以刷机了,手机开机启动后可以看到 /dev/socket 目录下服务端Socket已经成功启动了,如下图:
再来试一下,
https://blog.****.net/goleftgoright/article/details/7406292
关于Android应用与Framework的socket通信,相信关心这个问题的朋友们已经看过《android使用socket使底层和framework通信》这篇文章,美中不足的是作者只贴出一些关键的代码片段而并没有放出源码。我这里还是以一个能实际运行的例子为基础来讲,这样也方便大家学习。
首先看一下效果,如下图。我填写姓名"Potter",选择性别"Mr"然后点击发送,底层socket收到消息后将消息直接返回给我,我将返回的结果(Mr.Potter)直接显示在Result。
ok,有了初步了解后我们现在来看一下如何一步步实现这个例子。
1、配置init.rc。我在init.rc加入如下配置
- service htfskservice /system/bin/htfsk
- socket htfsk stream 666 system system
- oneshot
这里配置了一个名为 “htfskservice” 的服务,手机开机后该服务会自启动并运行/system/bin目录下的脚本htfsk(步骤二将提到如何生成这个脚本)。
同时这里还配置了一个名为 "htfsk" 的socket,并且只有拥有system权限的应用才允许连接这个socket,如何使应用获取system权限可以参考http://my.unix-center.net/~Simon_fu/?p=531这篇文章。
2、编写socket服务端代码,生成可执行脚本htfsk。
首先来看下socket服务端代码 htfsk.c ,内容如下:
- #define SOCKET_NAME "htfsk"
- #include <stdio.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <string.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <sys/socket.h>
- #include <sys/wait.h>
- #include <sys/un.h>
- #include <cutils/sockets.h>
- #include <utils/Log.h>
- #include <android/log.h>
- int main(){
- char log[200];
- int connect_number = 6;
- int fdListen = -1, new_fd = -1;
- int ret;
- struct sockaddr_un peeraddr;
- socklen_t socklen = sizeof (peeraddr);
- int numbytes ;
- char buff[256];
- //这一步很关键,就是获取init.rc中配置的名为 "htfsk" 的socket
- fdListen = android_get_control_socket(SOCKET_NAME);
- if (fdListen < 0) {
- sprintf(log,"Failed to get socket '" SOCKET_NAME "' errno:%d", errno);
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log);
- exit(-1);
- }
- //开始监听
- ret = listen(fdListen, connect_number);
- sprintf(log,"Listen result %d",ret);
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log);
- if (ret < 0) {
- perror("listen");
- exit(-1);
- }
- //等待Socket客户端发启连接请求
- new_fd = accept(fdListen, (struct sockaddr *) &peeraddr, &socklen);
- sprintf(log,"Accept_fd %d",new_fd);
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log);
- if (new_fd < 0 ) {
- sprintf(log,"%d",errno);
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log);
- perror("accept error");
- exit(-1);
- }
- while(1){
- //循环等待Socket客户端发来消息
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI","Waiting for receive");
- if((numbytes = recv(new_fd,buff,sizeof(buff),0))==-1){
- sprintf(log,"%d",errno);
- __android_log_write(ANDROID_LOG_DEBUG,"FTM_JNI",log);
- perror("recv");
- continue;
- }
- //发送消息回执给Socket客户端
- if(send(new_fd,buff,strlen(buff),0)==-1)
- {
- perror("send");
- close(new_fd);
- exit(0);
- }
- }
- close(new_fd);
- close(fdListen);
- return 0;
- }
写好服务端代码后我们要将他编译成可执行脚本htfsk,编译的Android.mk内容如下:
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS :=optional
LOCAL_C_INCLUDES := $(KERNEL_HEADERS)
LOCAL_SHARED_LIBRARIES := libcutils liblog
LOCAL_MODULE:= htfsk
LOCAL_SRC_FILES:=htfsk.c
LOCAL_PRELINK_MODULE := false
include $(BUILD_EXECUTABLE)
编译成功后就会在/system/bin/目录下找到生成的可执行脚本htfsk
3、编写客户端java代码。核心代码如下:
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.PrintWriter;
- import android.net.LocalSocket;
- import android.net.LocalSocketAddress;
- import android.util.Log;
- /**
- * Socket客户端
- *
- * @author lai_zs
- * @date:2012-3-17 下午12:15:09
- */
- public class SocketClient {
- private final String SOCKET_NAME = "htfsk";
- private LocalSocket client;
- private LocalSocketAddress address;
- private boolean isConnected = false;
- private int connetTime = 1;
- public SocketClient() {
- client = new LocalSocket();
- address = new LocalSocketAddress(SOCKET_NAME, LocalSocketAddress.Namespace.RESERVED);
- new ConnectSocketThread().start();
- }
- /**
- * 发送消息
- * @param msg
- * @return 返回Socket服务端的消息回执
- */
- public String sendMsg(String msg) {
- if (!isConnected) {
- return "Connect fail";
- }
- try {
- BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
- PrintWriter out = new PrintWriter(client.getOutputStream());
- out.println(msg);
- out.flush();
- return in.readLine();
- } catch (IOException e) {
- e.printStackTrace();
- }
- return "Nothing return";
- }
- /**
- * 异步连接Socket,如果连接不上会尝试重复连接十次
- *
- * @author Administrator
- *
- */
- private class ConnectSocketThread extends Thread {
- @Override
- public void run() {
- while (!isConnected && connetTime <= 10) {
- try {
- sleep(1000);
- Log.i("SocketClient","Try to connect socket;ConnectTime:"+connetTime);
- client.connect(address);
- isConnected = true;
- } catch (Exception e) {
- connetTime++;
- isConnected = false;
- Log.i("SocketClient","Connect fail");
- }
- }
- }
- }
- /**
- * 关闭Socket
- */
- public void closeSocket() {
- try {
- client.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
总结:经过以上三个步骤本实例就基本完成了,源码工程MySocket我已经上传至http://download.****.net/detail/goleftgoright/4183596
工程MySocket使用步骤:
1、配置init.rc。
2、将工程MySocket拷贝到android源码的/packages/apps目录下编译就可以了。
编译成功后就可以刷机了,手机开机启动后可以看到 /dev/socket 目录下服务端Socket已经成功启动了,如下图:
再来试一下,