项目中要用到进程间通讯,服务端接收应用的请求数据,对串口进行读写操作。考虑到android的socket服务比较实用,并且可以支持多个客户端同时连接。

服务端写成一个服务,在init.rc中启动,示例代码如下:

socket_keyboard.c:

#define LOG_TAG "socket-keyboard"#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <utime.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cutils/fs.h>
#include <cutils/sockets.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <cutils/multiuser.h>
#include <private/android_filesystem_config.h>
#define SOCKET_PATH "spi-keyboard"
//#define ALOGE LOGEvoid *thr_fn(void *arg)
{int s = (int)arg;char buf[1024];int count;char *respone = "this is from service";ALOGE("new thread: ");while (1) {ALOGE("read...");count = read(s,buf, sizeof(buf));if (count > 0) {buf[count] = '\0';ALOGE("read client:%s", buf);if (!memcmp(buf, "close", 5))break;}ALOGE("write...");count = write(s, respone, strlen(respone));}return NULL;
}int main(const int argc, const char *argv[]) {struct sockaddr addr;socklen_t alen;int lsocket, s;ALOGE("socket keyboard service start");lsocket = android_get_control_socket(SOCKET_PATH);if (lsocket < 0) {ALOGE("Failed to get socket from environment: %s\n", strerror(errno));exit(1);}if (listen(lsocket, 5)) {ALOGE("Listen on socket failed: %s\n", strerror(errno));exit(1);}ALOGE("socket keyboard service loop......");for (;;) {ALOGE("accept...");alen = sizeof(addr);s = accept(lsocket, &addr, &alen);if (s < 0) {ALOGE("Accept failed: %s\n", strerror(errno));continue;} else {int err;pthread_t ntid;err = pthread_create(&ntid, NULL, thr_fn, (void *)s);}  }ALOGE("service close");return 0;
}

客户端可以是c/c++代码,也可以是应用层代码,c代码如下:

#define LOG_TAG "socket-client"#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <utime.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <cutils/fs.h>
#include <cutils/sockets.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <cutils/multiuser.h>
#include <stdlib.h>
#include <stdio.h>
#include <stddef.h>
#include <sys/un.h>
#include <errno.h>
#include <private/android_filesystem_config.h>
#define SOCKET_PATH "socket-keyboard"#define ANDROID_RESERVED_SOCKET_PREFIX "/dev/socket/"
int main(const int argc, const char *argv[]) {char buf[1024] = {0};struct sockaddr_un addr;struct sockaddr_un *p_addr;socklen_t alen;int fd, s, count;size_t namelen;char *str = "this is from client";char *name = "spi-keyboard";p_addr = &addr;memset (p_addr, 0, sizeof (*p_addr));strcpy(p_addr->sun_path, ANDROID_RESERVED_SOCKET_PREFIX);strcat(p_addr->sun_path, name);p_addr->sun_family = AF_LOCAL;namelen = strlen(name) + strlen(ANDROID_RESERVED_SOCKET_PREFIX);alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;ALOGE("socket keyboard client start");fd = socket(PF_LOCAL, SOCK_STREAM, 0);if(connect(fd, (struct sockaddr *) &addr, alen) < 0) {ALOGE("connet spi keyboard server err[%s]", strerror(errno));exit(-1);}   while (1) {ALOGE("write");write(fd, str, strlen(str) + 1);ALOGE("read");count = read(fd, buf, sizeof(buf));if (count) {ALOGE("client: %s", buf);}sleep(1);}return 0;
}

客户端的c代码是仿照android socket源代码搬写过来的,源代码路径在system/core/libcutils/socket_local_client.c中。

Android.mk:

LOCAL_PATH := $(call my-dir)
#
# Executable
#include $(CLEAR_VARS)
LOCAL_SRC_FILES := \socket_keyboard.cLOCAL_SHARED_LIBRARIES := \libcutilsLOCAL_STATIC_LIBRARIES := \libdiskusage
LOCAL_MODULE := spi-keyboardLOCAL_MODULE_TAGS := optionalinclude $(BUILD_EXECUTABLE)include $(CLEAR_VARS)
LOCAL_SRC_FILES := \socket_client.cLOCAL_SHARED_LIBRARIES := \libcutilsLOCAL_STATIC_LIBRARIES := \libdiskusage
LOCAL_MODULE := socket-clientLOCAL_MODULE_TAGS := optionalinclude $(BUILD_EXECUTABLE)

把编译出来的执行文件放入/system/bin/目录,接着在init.rc中加入启动服务:

    service spi-keyboard /system/bin/spi-keyboardclass mainsocket spi-keyboard stream 777 user user

这里权限要更改成777 和 user,否则应用程序没有权限连接该服务。系统启动后在/dev/socket/目录下发现多了一个文件:

adbd                keystore            property_service    spi-keyboard
dnsproxyd           mdns                rild                vold
installd            netd                rild-debug          zygote         

这就是新的socket服务spi-keyboard。

执行./socket_client 即可连接上服务端。

应用层代码如下:

package com.example.keyboardsocketclient;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;import android.net.LocalSocket;
import android.net.LocalSocketAddress;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.Menu;public class MainActivity extends Activity {LocalSocket mSocket;InputStream mIn;OutputStream mOut;byte buf[] = new byte[1024];int ret = 0;String write_str = "this is from client******************************************";String write_str1 = "close";ServerSocketThread mthread;boolean isInterrupted = false;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mthread = new ServerSocketThread();mthread.start();}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}@Overrideprotected void onDestroy() {                                                                                                                               Log.d("spi-keyboard", "onDestroy");super.onDestroy();mthread.interrupt();finish();}   void connect() throws IOException {//创建socketmSocket = new LocalSocket();//设置连接地址LocalSocketAddress address = new LocalSocketAddress("spi-keyboard", LocalSocketAddress.Namespace.RESERVED);//建立连接mSocket.connect(address);//获取数据输入流 可以读数据mIn = mSocket.getInputStream();//获取数据输出流 可以写数据mOut = mSocket.getOutputStream();}private class ServerSocketThread extends Thread {public void interrupt(){isInterrupted = true;super.interrupt();}@Overridepublic void run() {try {connect();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}while (!isInterrupted) {//不能用this.isInterrupted()来判断,因为sleep时候,中断线程,只会catch异常,接着下一次循环中isInterrupted()还是为false  try {Thread.sleep(1000);//括号里面的5000代表5000毫秒,也就是5秒,可以该成你需要的时间} catch (InterruptedException e) {e.printStackTrace();}try {mOut.write(write_str.getBytes());} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}int count = 0;while (count == 0) {try {count = mIn.available();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}byte[] b = new byte[count];try {ret = mIn.read(b);} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}if (ret > 0) {String str = "";try {str = new String(b, "UTF-8");} catch (UnsupportedEncodingException e) {// TODO Auto-generated catch blocke.printStackTrace();}Log.e("keyboard client", "" + str);}}}}
}

运行该apk可以发现,服务端又为这个客户端创建一个线程,这样两个客户端可以同时连接,要注意LocalSocketAddress的第二个参数必须为LocalSocketAddress.Namespace.RESERVED,这个值为1,android专门为路径/dev/socket通讯而留的。

android socket通讯相关推荐

  1. Protobuf实现Android Socket通讯开发教程

    本节为您介绍Protobuf实现Android Socket通讯开发教程,因此,我们需要先了理一下protobuf 是什么? Protocol buffers是一种编码方法构造的一种有效而可扩展的格式 ...

  2. Android Socket通讯 之 心跳消息

    心跳消息 前言 正文 一.状态判断 二.心跳消息发送 三.心跳消息回复 四.源码 前言   不知道大家国庆节过的咋样,有没有学习呢?我是闲着没事就写点东西,本文篇幅较短,只是实现了心跳消息的处理,下面 ...

  3. android okhttpclient设置编码,Android之okhttp实现socket通讯(非原创)

    文章大纲 一.okhttp基础介绍二.socket通讯代码实战三.项目源码下载四.参考文章 一.okhttp基础介绍 二.socket通讯代码实战 1. 添加依赖和权限 app的build.gradl ...

  4. Android客户端与服务器端socket通讯

    Android客户端与服务器端的Socket通讯: socket通讯依赖IP地址和端口号,每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务. 服务器端代码: 实例化主类, ...

  5. Android模拟服务端下发消息的Socket通讯工具

    Android模拟服务端下发消息的Socket通讯工具 1. 背景简介 背景简介: 有些场景需要依赖服务端下发消息到客户端,比如PowerMsg,服务端下发消息Type,客户端解析Type做出相应动作 ...

  6. android模拟器socket服务端,android 模拟器跟电脑服务器端用socket通讯

    android 模拟器和电脑服务器端用socket通讯 之前一直会用sockets来实现emulator和PC进行通讯,卡了几天,最后请教其他人终于可以连接了.  错误原因是在IP和端口,IP要用本机 ...

  7. 获取android模拟器的IP地址,Android模拟器的ip获取以及模拟器之间socket通讯

    一.Android  获取本机Mac 地址方法:java 须要在AndroidManifest.xml文件中添加权限:android shell Java代码服务器 public String get ...

  8. android socket 发送byte_如何正确地创建和销毁网络通讯程序中的Socket类的对象实例...

    软件项目实训及课程设计指导--如何正确地创建和销毁软件应用系统中网络通讯中的Socket类的对象实例 1.基于TCP/IP协议的Socket通信相关的基础知识 (1)TCP/IP(Transmissi ...

  9. android socket第三方库,OkSocket 一个Android轻量级Socket通讯框架

    OkSocket Document An blocking socket client for Java application or Andorid. Open source licenses Ba ...

最新文章

  1. spring boot socket长连接_springboot 整合阿里 druid 数据库连接池实战
  2. Tomcat Server 配置
  3. 《机器学习实战》chapter05 Logistic回归
  4. Oracle查询数据库中所有表的记录数
  5. Bootstrap开发框架视频整理
  6. Spring Cloud 中 分布式事务解决方案 -- 阿里GTS的使用
  7. Git:小乌龟报错no supported authentication methods avaiable
  8. linux版本的redis bin,redis-4.0.2.tar.gz for centos的linux系统版本下载(安装详细步骤)...
  9. 《Python入门到精通》文件操作
  10. nginx启动时报错:bind() to 0.0.0.0:80 failed
  11. [Java] 蓝桥杯ADV-209 算法提高 c++_ch02_04
  12. layer自动补全 select
  13. select中常用的对象
  14. redis的set集合
  15. markDown 下载安装教程
  16. [4G+5G专题-132]: 传输层 - 以太网电缆的类型(Cat5,Cat5e,Cat6,Cat6a)
  17. 计算机图形学:DDA(数值微分)画线法
  18. 海洋cms常见问题有哪些?
  19. java string newline,Java BufferedWriter newLine()用法及代码示例
  20. VMWARE虚拟机网络环境配置

热门文章

  1. 数据库 、数据仓库、数据集市的区别与联系
  2. DSO Framer 使用介绍(ZZ)
  3. 未成年帐号登录华为游戏,启动后不断弹出防沉迷提示
  4. Java中的各种锁和数据库中的锁
  5. 再来30个!中国联通5G应用创新案例
  6. 谷歌浏览器chrome安装vuejs devtools 插件
  7. CAN总线协议报文浅析
  8. server sent event
  9. Linux各种打包和压缩文件命令
  10. Redis学习笔记(四):配置文件详细说明(redis-3.2)