android socket通讯

2023-05-16

项目中要用到进程间通讯,服务端接收应用的请求数据,对串口进行读写操作。考虑到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 LOGE

void *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.c

LOCAL_SHARED_LIBRARIES := \
	    libcutils

LOCAL_STATIC_LIBRARIES := \
	    libdiskusage
LOCAL_MODULE := spi-keyboard

LOCAL_MODULE_TAGS := optional

include $(BUILD_EXECUTABLE)

include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
	    socket_client.c

LOCAL_SHARED_LIBRARIES := \
	    libcutils

LOCAL_STATIC_LIBRARIES := \
	    libdiskusage
LOCAL_MODULE := socket-client

LOCAL_MODULE_TAGS := optional

include $(BUILD_EXECUTABLE)

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

    service spi-keyboard /system/bin/spi-keyboard
    class main
    socket 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;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);


        mthread = new ServerSocketThread();
        mthread.start();
    }


    @Override
    public 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;
    }
    @Override
    protected void onDestroy() {                                                                                                                               
        Log.d("spi-keyboard", "onDestroy");
        super.onDestroy();
        mthread.interrupt();
        finish();
    }   
    
    void connect() throws IOException 
    {
        //创建socket
        mSocket = 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();
	      }
        @Override
        public void run() {
            try {
                connect();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.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 block
                    e.printStackTrace();
                }


                int count = 0;
                while (count == 0) {
                    try {
                        count = mIn.available();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }


                byte[] b = new byte[count];


                try {
                    ret = mIn.read(b);
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }


                if (ret > 0) {
                    String str = "";
                    try {
                        str = new String(b, "UTF-8");
                    } catch (UnsupportedEncodingException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    Log.e("keyboard client", "" + str);
                }
            }
        }
    }
}



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



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

android socket通讯 的相关文章

  • Android SSL 无对等证书

    我有一个例外 没有同行证书 当我询问谷歌时 我得到了解决方案 我信任所有证书 但这个问题的答案是 它是不安全的 所以我给班级打电话 HostnameVerifier hostnameVerifier org apache http conn
  • Android 中的 JDBC 连接

    有没有人在 android 中尝试过 JDBC 连接 因为在 Android 2 3 中支持 JDBC 我必须在没有 Web 服务的情况下连接 Mysql 我已经提出申请 但它给了我错误 public class MysqlConnect
  • 如何将视图动态添加到已在 xml 布局中声明的relativelayout?

    我宣布了一个RelativeLayout在 xml 布局文件中 现在我想添加Views从代码到现有布局 我添加了一个Button通过代码动态地更改为现有布局 如下所示 rLayout RelativeLayout findViewById
  • 需要在 Android Studio 中使用 Team Foundation 客户端可能的替代方案/解决方法吗?

    我有一个场景 我需要使用 android studio 作为 IDE 使用 Team Foundation Server 作为源代码控制存储库 问题是android studio中没有TFS的插件 并且没有 TFS Windows 的独立客
  • Orientation改变时如何处理Activity?

    我正在编写一个活动 它从服务器加载数据并使用 ArrayAdapter 将其显示为列表 为此 我显示了一个进度对话框 即加载 同时它从服务器加载所有数据 然后我在处理程序中关闭该对话框 我的问题是 当我更改方向时 会再次显示进度对话框 这是
  • RecyclerView.OnScrollListener:一次滚动实例被多次调用

    我有一个水平布局的回收视图 一次只有一个视图可见 mRecyclerView findViewById R id rvmain mRecyclerView setOnFlingListener null final SnapHelper s
  • 如何使用 http 将 Android 中的文件从移动设备发送到服务器?

    在android中 如何使用http将文件 数据 从移动设备发送到服务器 很简单 您可以使用 Post 请求并将文件作为二进制 字节数组 提交 String url http yourserver File file new File En
  • 我应该保留远程数据库的本地副本吗?

    我正在开发一个应用程序 基本上允许人们创建 加入和管理其他人的群组 群组内的人也可以互相发送消息 我一直在想哪条路会更好 保留包含所有信息的远程数据库 包括发送给用户和从用户发送的消息 并让应用程序在每次需要信息时查询服务器 甚至是它以前见
  • 动画图像视图

    目前我正在开发一款游戏 这是我的游戏的详细信息 用户应选择正确的图像对象 我希望图像从左到右加速 当他们到达终点时 他们应该再次出现在活动中 这是我正在处理的屏幕截图 我有 5 个图像视图 它们应该会加速 您有此类动画的示例代码吗 非常感谢
  • sqlite 插入表中 select * from

    我需要在 Android 应用程序中将数据从一个表移动到另一个表 我想使用以下sql insert into MYTABLE2 select id STATUS risposta DATETIME now data ins from MYT
  • Galaxy Nexus 4.1.1 和 ISO14443 读卡器

    是否可以在 Galaxy Nexus Jelly Bean 4 1 1 移动设备和任何常规桌面非接触式读卡器 ISO 14443 A B 之间建立连接 据我所知 android不支持卡模拟模式 所以只能通过p2p模式来完成 p2p 是否基于
  • 使用MockWebServer暂停功能测试

    我正在测试使用 MockWebServer 的挂起函数返回结果的 api 但它不适用于 runBlockingTest testCoroutineDispatcher testCorounieScope 除非launch使用builder
  • 膨胀类片段 InflateException 二进制 XML 文件时出错

    我正在使用 Material Design 和 NavigationDrawer 布局等设计我的第一个应用程序 但我遇到了一个问题 该应用程序非常简单 它只显示文本 并且基于 Android Studio 中提供的模板 尝试启动我的应用程序
  • 更改弹出对话框的背景颜色

    我编写了显示弹出对话框的 android 代码 但我想将背景颜色从黑色更改为白色 然后更改文字颜色 这是对话框的代码 mPrefs PreferenceManager getDefaultSharedPreferences this Boo
  • 无法仅在控制台中启动 androidstudio

    你好 我的问题是下一个 我下载了Android Studio如果我去 路径 android studio bin 我执行studio sh 我收到以下错误 No JDK found Please validate either STUDIO
  • 将 espresso 与自定义 EditText 结合使用

    这是我的布局的一部分
  • Android 4 上的 html5 视频:全屏播放然后重定向到另一个网页 - 不起作用

    我正在为 Android 4 智能手机设计一个 html5 页面 其中包含一个 3gpp 或 mp4 视频 打开时必须自动全屏播放 当视频结束时应该重定向到另一个网址 一些谷歌搜索告诉我 Android 4 上不再允许自动播放 因此我选择显
  • 无法在 BlackBerry Playbook 上设置音量

    我在更改黑莓游戏书的音量时遇到问题 首先 我将 Android 应用程序重新打包到 Palybook 应用程序 我需要使用搜索栏更改黑莓剧本的音量 并在搜索监听器中设置音频管理器音量 这是代码 audioManager AudioManag
  • Android 键盘清单未显示在设置中

    我正在制作我的第一个 Android 应用程序 我需要它作为键盘服务 据我所知 清单看起来不错 并且我有一个文件 WifiJoy java 在 com zwad3 wifijoy 包中 以及所有其他文件
  • 按照说明后“找不到您尝试购买的商品”

    所以我按照以下说明进行操作http developer android com google play billing billing admin html http developer android com google play bi

随机推荐

  • java 35 个 Java 代码性能优化总结

    前言 代码优化 xff0c 一个很重要的课题 可能有些人觉得没用 xff0c 一些细小的地方有什么好修改的 xff0c 改与不改对于代码的运行效率有什么影响呢 xff1f 这个问题我是这么考虑的 xff0c 就像大海里面的鲸鱼一样 xff0
  • 基于51单片机超声波红外避障语音导盲仪设计(全套资料)

    基于51单片机的超声波红外避障语音导盲仪设计 本系统采用STC89C52单片机 43 4位高亮白色LED灯 43 红外避障传感器电路 43 超声波电路 43 光敏电阻模块 43 语音报警电路 43 震动电路 43 液晶1602电路 43 电
  • linux 解压zip压缩包命令

    unzip 文件名 zip d 解压位置 例如 xff1a unzip 微信 zip d demowx
  • linux 文件授权命令

    文件授权 chmod 43 x sh
  • linux tomcat常用命令

    startup sh 启动tomcat shutdown sh 关闭tomcat ps ef grep tomcat 查看Tomcat运行 kill 9 4723 杀进程 tail f catalina out 查看tomcat运行日志 c
  • linux redis常用命令

    flushall 清空redis缓存 redis cli 进入redis xff08 需要进入redis的安装目录下 xff09 get key 查找key del key 删除key
  • java DateUtils时间工具栏

    package com eeye common utils import org apache commons lang3 time DateFormatUtils import java text ParseException impor
  • unity3d:Astar寻路,A星,A*,二叉堆优化Open表

    原理视频 油管 xff1a https youtu be i0x5fj4PqP4 别人的B站翻译 xff1a https www bilibili com video BV1v44y1h7Dt spm id from 61 333 999
  • TCP/IP 、HTTP、Socket的区别与联系

    1 Socket和http的区别 http xff1a 如何封装数据 xff1b 基于TCP协议 xff0c 简单的对象访问协议 xff0c 对应于应用层 xff1b xff08 货物 xff09 tcp协议 xff1a 数据在网络中的传输
  • 【亲测一次成功】将本地代码上传到Gitee码云

    1 在Gitee码云上创建仓库 2 在本地新建一个文件夹 3 右击新建的文件夹 xff0c 使用git bush here 4 输入 git init 5 输入 git remote add origin 43 仓库地址 6 输入 git
  • keil5打开工程报错:error:not found device

    1 error not found device 解决方法 xff1a 将Project文件夹中的工程扩展名由 uvproj改为 uvprojx 原因 xff1a 前提是所有的库安装都是正常且正确的 xff0c 所以应该是如下问题 xff1
  • STM32学习笔记:IWDG_独立看门狗

    1 简介 独立看门狗就是一个12位的递减计数器 xff0c 最大值0xFFF xff1b 计数器的值从某一个值减到0时 xff0c 系统产生一个复位信号 xff08 IWDG RESET xff09 xff1b 在计数器没减到0之前 xff
  • 基于单片机避障导盲智能拐杖控制设计(毕设资料)

    本设计研究为盲人提供行走时 xff0c 遇到前方障碍物提前躲避的智能避障预警系统 以AT89S52单片机作为核心处理器 xff0c 采用超声波回波时间差测量人与物体之间的安全距离 xff0c 实现了提前预警使用者避让障碍物 xff0c 起到
  • Matlab:excel文件 转 txt文件 (只需2行代码)

    亲测有用 xff0c 只需两行代码 xff0c 将EXCEL文件 xff0c 转换成txt文件 xff1a Data 61 readtable 39 TEST xls 39 writetable Data 39 test txt 39 ex
  • 快速理解C语言——指针

    1 地址和内存 把值存在内存中 xff0c 内存就给每一个值分配一个地址 xff1a 100 104 108 112 116就是每个值分别对应的地址 xff1b 给每个内存地址起个别名 xff0c 就是 xff1a 变量 2 值和类型 如下
  • 亲测有用!完美关闭win10不断自动更新

    自从更新到win10以来 xff0c 每次开关机都会遇到win10更新的问题 试过CSDN和其他很多种方法都没有用 xff0c 最后在知乎上看到一个大神写的 用以下方法完美解决 xff0c 再没出现过自动更新的问题 如何完美解决win10自
  • 一文解决所有PCA问题——这是我看过最好的讲解PCA理论文章

    转载 xff1a http blog codinglabs org articles pca tutorial html PCA xff08 Principal Component Analysis xff09 是一种常用的数据分析方法 P
  • C语言解析http协议

    C语言解析http协议 1 关键解析函数1 1 strstr xff08 xff09 1 2 strncmp 2 代码 1 关键解析函数 1 1 strstr xff08 xff09 函数原型 xff1a span class token
  • 大小端问题

    本来我想说 xff0c Windows平台一般是小端 xff0c Linux一般是大端 xff1b 但是 实际上大小端CPU架构有关 xff0c 当然和系统也可能有关 xff0c 可以配置大小端 xff1b 对于CPU框架 xff0c AR
  • android socket通讯

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