Android中的socket本地通讯框架
一、先分析Native层:
1、C++基类SocketListener:
- class SocketListener {
- int mSock;
- const
char *mSocketName; - SocketClientCollection *mClients;
- pthread_mutex_t mClientsLock;
- bool mListen;
- int mCtrlPipe[2];
- pthread_t mThread;
- public:
- SocketListener(const
char *socketNames, bool listen); - SocketListener(int socketFd, bool listen);
- virtual ~SocketListener();
- int startListener();
- int stopListener();
- void sendBroadcast(int code, const
char *msg, bool addErrno); - void sendBroadcast(const
char *msg); - protected:
- virtual bool onDataAvailable(SocketClient *c) = 0;
- private:
- static
void *threadStart(void *obj); - void runListener();
- };
- #endif
看关键接口runListener:
- void SocketListener::runListener() {
- while(1) {
- SocketClientCollection::iterator it;
- fd_set read_fds;
- int rc = 0;
- int max = 0;
- FD_ZERO(&read_fds);
- if (mListen) {
- max = mSock;
- FD_SET(mSock, &read_fds);
- }
- FD_SET(mCtrlPipe[0], &read_fds);
- if (mCtrlPipe[0] > max)
- max = mCtrlPipe[0];
- pthread_mutex_lock(&mClientsLock);
- for (it = mClients->begin(); it != mClients->end(); ++it) {
- FD_SET((*it)->getSocket(), &read_fds);
- if ((*it)->getSocket() > max)
- max = (*it)->getSocket();
- }
- pthread_mutex_unlock(&mClientsLock);
- if ((rc = select(max + 1, &read_fds, NULL, NULL, NULL)) < 0) {
- SLOGE("select failed (%s)", strerror(errno));
- sleep(1);
- continue;
- } else
if (!rc) - continue;
- if (FD_ISSET(mCtrlPipe[0], &read_fds))
- break;
- if (mListen && FD_ISSET(mSock, &read_fds)) {
- struct sockaddr addr;
- socklen_t alen = sizeof(addr);
- int c;
- if ((c = accept(mSock, &addr, &alen)) < 0) {
- SLOGE("accept failed (%s)", strerror(errno));
- sleep(1);
- continue;
- }
- pthread_mutex_lock(&mClientsLock);
- mClients->push_back(new SocketClient(c));
- pthread_mutex_unlock(&mClientsLock);
- }
- do {
- pthread_mutex_lock(&mClientsLock);
- for (it = mClients->begin(); it != mClients->end(); ++it) {
- int fd = (*it)->getSocket();
- if (FD_ISSET(fd, &read_fds)) {
- pthread_mutex_unlock(&mClientsLock);
- if (!onDataAvailable(*it)) {//由子类实现的接口。
- close(fd);
- pthread_mutex_lock(&mClientsLock);
- delete *it;
- it = mClients->erase(it);
- pthread_mutex_unlock(&mClientsLock);
- }
- FD_CLR(fd, &read_fds);
- continue;
- }
- }
- pthread_mutex_unlock(&mClientsLock);
- } while (0);
- }
- }
2、他的第一继承者:
- #include "SocketListener.h"
- #include "FrameworkCommand.h"
- class SocketClient;
- class FrameworkListener : public SocketListener {
- public:
- static
const
int CMD_ARGS_MAX = 16; - private:
- FrameworkCommandCollection *mCommands;
- public:
- FrameworkListener(const
char *socketName); - virtual ~FrameworkListener() {}
- protected:
- void registerCmd(FrameworkCommand *cmd);
- virtual
bool onDataAvailable(SocketClient *c); - private:
- void dispatchCommand(SocketClient *c, char *data);
- };
他的onDataAvailable接口实现:
- bool FrameworkListener::onDataAvailable(SocketClient *c) {
- char buffer[255];
- int len;
- if ((len = read(c->getSocket(), buffer, sizeof(buffer) -1)) < 0) {
- SLOGE("read() failed (%s)", strerror(errno));
- return errno;
- } else
if (!len) - return
false; - int offset = 0;
- int i;
- for (i = 0; i < len; i++) {
- if (buffer[i] == '\0') {
- dispatchCommand(c, buffer + offset);
- offset = i + 1;
- }
- }
- return
true; - }
3、实例:netd的CommandListener类:
- class CommandListener : public FrameworkListener {
- static TetherController *sTetherCtrl;
- static NatController *sNatCtrl;
- static PppController *sPppCtrl;
- static PanController *sPanCtrl;
- static SoftapController *sSoftapCtrl;
- static UsbController *sUsbCtrl;
- public:
- CommandListener();
- virtual ~CommandListener() {}
- private:
- static
int readInterfaceCounters(const
char *iface, unsigned long *rx, unsigned long *tx); - class UsbCmd : public NetdCommand {
- public:
- UsbCmd();
- virtual ~UsbCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- class SoftapCmd : public NetdCommand {
- public:
- SoftapCmd();
- virtual ~SoftapCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- class InterfaceCmd : public NetdCommand {
- public:
- InterfaceCmd();
- virtual ~InterfaceCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- class IpFwdCmd : public NetdCommand {
- public:
- IpFwdCmd();
- virtual ~IpFwdCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- class TetherCmd : public NetdCommand {
- public:
- TetherCmd();
- virtual ~TetherCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- class NatCmd : public NetdCommand {
- public:
- NatCmd();
- virtual ~NatCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- class ListTtysCmd : public NetdCommand {
- public:
- ListTtysCmd();
- virtual ~ListTtysCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- class PppdCmd : public NetdCommand {
- public:
- PppdCmd();
- virtual ~PppdCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- class PanCmd : public NetdCommand {
- public:
- PanCmd();
- virtual ~PanCmd() {}
- int runCommand(SocketClient *c, int argc, char ** argv);
- };
- };
不能忘记NetdCommand类:
- #include <sysutils/FrameworkCommand.h>
- class NetdCommand : public FrameworkCommand {
- public:
- NetdCommand(const
char *cmd); - virtual ~NetdCommand() {}
- };
- 4、分析一个子类ListTtysCmd:
- CommandListener::ListTtysCmd::ListTtysCmd() :
- NetdCommand("list_ttys") {
- }
- int CommandListener::ListTtysCmd::runCommand(SocketClient *cli,
- int argc, char **argv) {
- TtyCollection *tlist = sPppCtrl->getTtyList();
- TtyCollection::iterator it;
- for (it = tlist->begin(); it != tlist->end(); ++it) {
- cli->sendMsg(ResponseCode::TtyListResult, *it, false);
- }
- cli->sendMsg(ResponseCode::CommandOkay, "Ttys listed.", false);
- return 0;
- }
Java层:
- private
void listenToSocket() throws IOException { - LocalSocket socket = null;
- try {
- socket = new LocalSocket();
- LocalSocketAddress address = new LocalSocketAddress(mSocket,
- LocalSocketAddress.Namespace.RESERVED);
- socket.connect(address);
- InputStream inputStream = socket.getInputStream();
- mOutputStream = socket.getOutputStream();
- mCallbacks.onDaemonConnected();
- byte[] buffer = new
byte[BUFFER_SIZE]; - int start = 0;
- while (true) {
- int count = inputStream.read(buffer, start, BUFFER_SIZE - start);
- if (count < 0) break;
- // Add our starting point to the count and reset the start.
- count += start;
- start = 0;
- for (int i = 0; i < count; i++) {
- if (buffer[i] == 0) {
- String event = new String(buffer, start, i - start);
- if (LOCAL_LOGD) Slog.d(TAG, String.format("RCV <- {%s}", event));
- String[] tokens = event.split("
", 2); - try {
- int code = Integer.parseInt(tokens[0]);
- if (code >= ResponseCode.UnsolicitedInformational) {
- mCallbackHandler.sendMessage(
- mCallbackHandler.obtainMessage(code, event));
- } else {
- try {
- mResponseQueue.put(event);
- } catch (InterruptedException ex) {
- Slog.e(TAG, "Failed to put response onto queue", ex);
- }
- }
- } catch (NumberFormatException nfe) {
- Slog.w(TAG, String.format("Bad msg (%s)", event));
- }
- start = i + 1;
- }
- }
- // We should end at the amount we read. If not, compact then
- // buffer and read again.
- if (start != count) {
- final int remaining = BUFFER_SIZE - start;
- System.arraycopy(buffer, start, buffer, 0, remaining);
- start = remaining;
- } else {
- start = 0;
- }
- }
- } catch (IOException ex) {
- Slog.e(TAG, "Communications error", ex);
- throw ex;
- } finally {
- synchronized (mDaemonLock) {
- if (mOutputStream != null) {
- try {
- mOutputStream.close();
- } catch (IOException e) {
- Slog.w(TAG, "Failed closing output stream", e);
- }
- mOutputStream = null;
- }
- }
- try {
- if (socket != null) {
- socket.close();
- }
- } catch (IOException ex) {
- Slog.w(TAG, "Failed closing socket", ex);
- }
- }
- }
sendCommandLocked接口
- /**
- * Sends a command to the daemon with a single argument
- *
- * @param command The command to send to the daemon
- * @param argument The argument to send with the command (or null)
- */
- private
void sendCommandLocked(String command, String argument) - throws NativeDaemonConnectorException {
- if (command != null && command.indexOf('\0') >= 0) {
- throw
new IllegalArgumentException("unexpected command: " + command); - }
- if (argument != null && argument.indexOf('\0') >= 0) {
- throw
new IllegalArgumentException("unexpected argument: " + argument); - }
- if (LOCAL_LOGD) Slog.d(TAG, String.format("SND -> {%s} {%s}", command, argument));
- if (mOutputStream == null) {
- Slog.e(TAG, "No connection to daemon", new IllegalStateException());
- throw
new NativeDaemonConnectorException("No output stream!"); - } else {
- StringBuilder builder = new StringBuilder(command);
- if (argument != null) {
- builder.append(argument);
- }
- builder.append('\0');
- try {
- mOutputStream.write(builder.toString().getBytes());
- } catch (IOException ex) {
- Slog.e(TAG, "IOException in sendCommand", ex);
- }
- }
- }
Android中的socket本地通讯框架的更多相关文章
- Android中基于Socket的网络通信
1. Socket介绍 2. ServerSocket的建立与使用 3. 使用ServerSocket建立聊天服务器-1 4. 使用ServerSocket建立聊天服务器-2 5. 在Android中 ...
- Android多媒体开发-- android中OpenMax的实现整体框架
1.android中用openmax来干啥? android中的AwesomePlayer就 是用openmax来做(code)编解码,其实在openmax接口设计中,他不光能用来当编解码.通过他的组 ...
- 【Spring Boot】集成Netty Socket.IO通讯框架
服务端 @Configuration public class NettySocketConfig { private static final Logger logger = LoggerFacto ...
- 34、Android中基于Socket的网络通信(一)
Socket又称”套接字”,应用程序通常通过”套接字”向网络发出请求或者应答网络请求. 在java中,Socket和ServerSocket类库位于java.net包中,ServerSocket用于服 ...
- Android中通过访问本地相册或者相机设置用户头像
目前几乎所有的APP在用户注册时都会有设置头像的需求,大致分为三种情况: (1)通过获取本地相册的图片,经过裁剪后作为头像. (2)通过启动手机相机,现拍图片然后裁剪作为头像. (3)在APP中添加一 ...
- android中利用Socket实现手机客户端与PC端进行通信
1. 项目截图
- Android中常用的优秀开源框架
Android开源框架库分类,挑选出最常用,最实用的开源项目,本篇主要介绍的是优秀开源框架库和项目,UI个性化控件会独立介绍.UI个性化控件 Index Dependency Injections A ...
- Android中Universal Image Loader开源框架的简单使用
UIL (Universal Image Loader)aims to provide a powerful, flexible and highly customizable instrument ...
- android 中activity调用本地service中的方法。
1.自定义一个接口,暴露服务中的方法 public interface IService { /**服务中对外暴露的方法 */ void methodInService();} 2.自定一 ...
随机推荐
- maven 常用脚本
Maven库: http://repo2.maven.org/maven2/ Maven依赖查询: http://mvnrepository.com/ Maven常用命令: 1. 创建Maven的普通 ...
- 业务逻辑 : forex & mlm
业务逻辑 公司通过mlm的制度和顾客进行签约来收取资金,再把资金给第三方公司进行投资,再把所投资的回报给分配给公司和顾客. 公司的资金来自投资者,公司的营销策略来自mlm的制度,由市场人员来创建mlm ...
- 徒手用Java来写个Web服务器和框架吧<第二章:Request和Response>
徒手用Java来写个Web服务器和框架吧<第一章:NIO篇> 接上一篇,说到接受了请求,接下来就是解析请求构建Request对象,以及创建Response对象返回. 多有纰漏还请指出.省略 ...
- 9 个用于移动APP开发的顶级 JavaScript 框架
顶级 Java 框架 对于Web开发而言,Java是一个有前途的编程语言,并且在不久的将来它将依然在这个领域大放光彩.Java在移动app开发上也有同样的影响吗?让我们一起来看看ValueCoders ...
- 你知道自己执行的是哪个jre吗?
多个JRE 我在做<Java日志工具之java.util.logging.Logger>的DEMO时,修改java.util.logging.Logger的配置文件,怎么修改都不起作用,因 ...
- Delete Node in a Linked List leetcode
Write a function to delete a node (except the tail) in a singly linked list, given only access to th ...
- 每天一个Linux命令 9
Linux常用命令: 压缩命令:gzip 解压命令:gunzip 压缩命令:zip 解压命令:unzip 压缩命令:bzip2 解压命令:bunzip2 压缩打包命令:tar 1.命令名称:gzi ...
- react学习总结
http://www.runoob.com/react/react-tutorial.html一般先看一些中文的简单的介绍和一些基本概念http://reactjs.cn/react/docs/get ...
- SEO-站内优化规范
类别 要求 实际工作要求 程 序 设 计 1.DIV+CSS布局 2.站内导航连接性良好 面包屑导航,翻页方式使用样式二,文章和产品上一页和下一页 3.图片的ALT属性 在编程时注意写 4.超级链接的 ...
- 记 suds 模块循环依赖的坑-RuntimeError: maximum recursion depth exceeded
下面是soa接口调用的核心代码 #! /usr/bin/python # coding:utf-8 from suds.client import Clientdef SoaRequest(wsdl, ...