使用 Java 在 Android 平台上通过 socket 实现进程间通信

news2024/9/20 1:03:33

引言

Socket是位于应用层和传输层之间的一个抽象层,把TCP/IP层复杂的操作抽象为几个简单的接口,供应用层调用以实现进程在网络中通信。
Socket分为流式套接字和数据包套接字,分别对应网络传输控制层的TCP协议和UDP协议。TCP协议是一种面向连接的,可靠的,基于字节流的传输层通信协议,它使用三次握手协议建立连接,并且提供了超时重传机制,具有很高的稳定性。UDP协议是一种无连接的协议,且不对数据包进行可靠性保证。
在网络差的情况下,UDP协议数据包丢失会比较严重,但由于其不属于连接型协议,具有资源消耗少,处理速度快的优点,在音频视频等传输时使用UDP协议较多。

示例

这里我们通过socket实现两个进程之间的通信。

  1. 建立两个工程,分别是TestServerSocket和TestClientSocket,并分别增加权限。
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
  1. TestServerSocket
    当server service启动的时候,创建ServerSocket,对端口8688进行监听;然后进行while循环,在循环中阻塞线程直到接收到客户端消息;收到客户端消息的时候会收到客户端的Socket,然后开启while循环,通过InputStream获取其消息,通过OutputStream向其发送消息。
  • MainActivity
    @Override
    protected void onResume() {
        super.onResume();
        startService(new Intent(this,SocketServerService.class));
    }
  • SocketServerService
public class SocketServerService extends Service {
    private boolean isServiceDestroyed = false;
    private static final String TAG = "SocketServerService";
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        new Thread(new TcpServer()).start();
    }
    private class TcpServer implements Runnable{
        @Override
        public void run() {
            ServerSocket serverSocket = null;
            try{
                serverSocket = new ServerSocket(8688);
            }catch (IOException exception){
                exception.printStackTrace();
            }
            while(!isServiceDestroyed){
                try {
                    if (serverSocket == null){
                        return;
                    }
                    Log.i(TAG, "ServerSocket loop listen ClientSocket");
                    //接收客户端的请求,并且阻塞直到接收到消息
                    final Socket client = serverSocket.accept();
                    new Thread(() -> {
                        try {
                            responseClient(client);
                        } catch (IOException exception) {
                            exception.printStackTrace();
                        }
                    }).start();
                }catch (IOException exception){
                    exception.printStackTrace();
                }
            }

        }
    }
    private void responseClient(Socket client) throws IOException{
        // 用于接收客户端的消息
        BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
        // 用于向客户端发送消息
        PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                client.getOutputStream())),true);
        out.println("你好,我是服务端");
        while(!isServiceDestroyed){
            String str = in.readLine();
            Log.i(TAG, "收到客户端发来的消息" + str);
            if (TextUtils.isEmpty(str)){
                //客户端断开了连接
                Log.i(TAG, "客户端断开了连接");
                break;
            }
            String message = "收到了客户端的消息为:" + str;
            // 从客户端收到的消息加工再发送给客户端
            out.println(message);
        }
        out.close();
        in.close();
        client.close();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        isServiceDestroyed = true;
    }
}

3.TestClientSocket
客户端首先就是开启while循环,创建Socket与ServerSocket进行连接,直到建立与ServerSocket的连接;然后同样是获得ServerSocket,通过InputStream读取其内容,通过OutputStream向其写入内容。

public class MainActivity extends AppCompatActivity {

    private PrintWriter mPrintWriter;
    private EditText mEt_receive;
    private TextView mTv_message;
    private static final String TAG = "TestClientService";
    private Handler mHandler = new Handler(new Handler.Callback() {
        @Override
        public boolean handleMessage(@NonNull Message message) {
            mTv_message.setText(String.format("%s\n客户端:%s", mTv_message.getText(), message.obj));
            mEt_receive.setText("");
            return true;
        }
    });

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        new Thread(this::connectSocketServer).start();
    }

    private void initView() {
        mEt_receive = findViewById(R.id.et_receive);
        Button mBt_send = findViewById(R.id.bt_send);
        mTv_message = findViewById(R.id.tv_message);
        mBt_send.setOnClickListener(view -> {
            final String msg = mEt_receive.getText().toString();
            //向服务器发送消息
            if (!TextUtils.isEmpty(msg) && null!=mPrintWriter){
                new Thread(() -> {
                    mPrintWriter.println(msg);
                    Message message = Message.obtain();
                    message.what = 0;
                    message.obj = msg;
                    mHandler.sendMessage(message);
                }).start();
            }
        });
    }

    private void connectSocketServer() {
        Socket socket = null;
        while (socket == null){
            try {
                //选择和服务器相同的ip和端口 8688
                socket = new Socket("192.168.1.3",8688);
                mPrintWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
                        socket.getOutputStream())),true);
            }catch (IOException exception){
                Log.d(TAG, "connectSocketServer: " + exception);
                SystemClock.sleep(1000);
            }
        }
        try {
            // 用于接收服务端的消息
            BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while(!isFinishing()){
                final String msg = br.readLine();
                if (msg != null){
                    runOnUiThread(() ->
                            mTv_message.setText(
                            String.format("%s\n服务端:%s", mTv_message.getText(), msg)));
                }
            }
            mPrintWriter.close();
            br.close();
            socket.close();
        }catch (IOException exception){
            exception.printStackTrace();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mHandler.removeCallbacksAndMessages(null);
        mHandler = null;
    }
}
  1. 先打开服务端
2022-04-30 ... com.example.testserversocket I/SocketServerService: ServerSocket loop listen ClientSocket

4.再打开客户端
客户端开启之后建立与服务端的连接。
客户端建立了与服务端的连接.jpg
连接创建好之后,客户端向服务端发送信息。
服务端收到了客户端发送的信息.jpg

2022-04-30 ... com.example.testserversocket I/SocketServerService: 收到客户端发来的消息你好,我是客户端

总结

在上层,socket基于对相同IP和相同端口的监听实现的。

参考

刘望舒的Android进阶指北。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2083093.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Qt之界面优化

目录 前言 QSS基础知识 选择器 样式属性 控件样式⽰例 绘图 接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗-----------林辞忧 前言 Qt 仿照CSS的模式,引⼊了QSS,来对Qt中的控件做出样式上的设定,从⽽允许程序猿写出界⾯更好看 的代码.当然,由于Q…

【面试题系列Vue05】跟其他人不太一样的 Vue生命周期总结

既然要讲 生命周期&#xff0c;那渲染过程得先了解下。 数据绑定 Vue 文本插值 在 Vue 中&#xff0c;最基础的模板语法是数据绑定&#xff0c;例如&#xff1a; <div>{{ data }}</div>这里绑定了一个 msg 的变量&#xff0c;开发者在 Vue 实例 data 中绑定该变…

DataWhale AI夏令营-《李宏毅深度学习教程》笔记-task2

DataWhale AI夏令营-《李宏毅深度学习教程》笔记 第四章 卷积神经网络卷积神经网络构成一个通俗的例子 第四章 卷积神经网络 这部分看书的时候感觉云里雾里的&#xff0c;好在之前学过一些卷积神经网络、全链接、感受野的概念&#xff0c;我就用自己的理解阐述一篇笔记吧&…

idea插件开发(一)合并检查

一、引言 由于代码合并冲突的时候&#xff0c;代码丢失的情况频发&#xff0c;作者研究idea的VFS虚拟文件系统和Git4ide源码&#xff0c;创作idea插件检测代码合并丢失 可以区分主动删除与被动丢失&#xff0c;比如本地或者删除一段代码&#xff0c;合并之后不会被认为是丢失…

华为云 x 容联云|828企业节,助推中国数智产业实力再升级

2024年8月27日&#xff0c;华为第三届828 B2B企业节在2024中国国际大数据产业博览会上正式开幕。 828 B2B企业节是全国首个基于数字化赋能的企业节&#xff0c;由华为联合上万家生态伙伴共同发起&#xff0c;旨在为广大企业尤其是中小企业搭建数字化创新发展平台&#xff0c;融…

C语言基础(二十二)

在C语言中&#xff0c;对链表进行排序涉及到比较链表中的节点值&#xff0c;并根据比较结果重新排列这些节点。由于链表是非连续存储的数据结构&#xff0c;其排序比数组排序要复杂一些。由链表的结构特性可知&#xff0c;插入排序和归并排序更适合链表排序。 测试代码1&#…

力扣之1853.转换日期格式

文章目录 1. 1853.转换日期格式1.1 题干1.2 建表1.3 题解1.4 实现方式1.5 题解1.6 知识总结 1. 1853.转换日期格式 1.1 题干 表: Days ----------------- | Column Name | Type | ----------------- | day | date | ----------------- day 是这个表的主键。 给定一个Days表&…

基于Spring Boot的陶瓷文化网站的设计与实现

毕业设计&#xff08;论文&#xff09; 论文题目&#xff1a;基于Spring Boot的陶瓷文化网站的设计与实现 博主可接毕设论文&#xff01;&#xff01;&#xff01; 摘 要 中国悠久的陶瓷艺术&#xff0c;作为民族文化遗产的重要载体&#xff0c;历经时代的洗礼&#xff0c;其…

kube-scheduler组件的启动流程与源码走读

概述 摘要&#xff1a;kube-scheduler是kubernetes系统中的重要组件&#xff0c;kub-scheduler 的核心职责是为待调度的 pod 寻找一个最合适的 node 节点, 然后进行 bind node 绑定, 后面 kubelet 才会监听到并创建真正的 pod。kub-scheduler本身是一个功能强大且负责的核心组…

使用Axure打造智慧场景下的数据可视化大屏原型

在数字化转型的浪潮中&#xff0c;数据可视化大屏以其直观、动态、高效的特性&#xff0c;成为了智慧社区、智慧城市、智慧工厂、智慧园区等各个领域不可或缺的展示窗口。作为专业的原型设计软件&#xff0c;Axure不仅以其强大的交互设计能力著称&#xff0c;更在数据可视化大屏…

线段树小例题——结合前后缀获得结果

和我今天上午写的那个前后缀太像了&#xff0c;不能说一模一样&#xff0c;但是至少我觉得思路是真的一点没变 上一道题的链接&#xff1a;http://t.csdnimg.cn/pXBnU P4513 小白逛公园 题意&#xff1a;有n个点&#xff0c;每个点都有一个初值&#xff0c;然后有m个操作&am…

SQL慢查询优化方式

目录 一、SQL语句优化 1. 避免使用 SELECT * &#xff0c;而是具体字段 2.避免使用 % 开头的 LIKE 的查询 3.避免使用子查询&#xff0c;使用JOIN 4.使用EXISTS代替IN 5.使用LIMIT 1优化查询 6.使用批量插入、优化INSERT操作 7.其他方式 二、SQL索引优化 1.在查询条件…

Java异常详解(全文干货)

介绍 Throwable Throwable 是 Java 语言中所有错误与异常的超类。 Throwable 包含两个子类&#xff1a;Error&#xff08;错误&#xff09;和 Exception&#xff08;异常&#xff09;&#xff0c;它们通常用于指示发生了异常情况。 Throwable 包含了其线程创建时线程执行堆栈…

分库分表学习笔记(二)

分库分表学习笔记&#xff08;一&#xff09;-CSDN博客 分表分库规则 图源&#xff08;https://zhuanlan.zhihu.com/p/535713197&#xff09; 水平分表 水平分表一般是我们数据库的数据太多了&#xff0c;原大众点评的订单单表早就已经突破两百G。 数据量太多的影响 1. 查询…

linux dma cache和主存数据不一致问题

1、问题原因 根本原因是cache和dma的目的地址存在重叠。 如果DMA的目的地址与Cache所缓存的内存地址访问有重叠&#xff08;如上图所示&#xff09; &#xff0c; 经过DMA操作&#xff0c; 与Cache缓存对应的内存中的数据已经被修改&#xff0c; 而CPU本身并不知道&#xff0c…

VScode开发ESP32

以下是所有的功能 先选择串口&#xff0c;再选择编译&#xff0c;然后再烧录

2023年最新自适应主题懒人网址导航v3.9php源码

源码简介 这个懒人网址导航源码是一个基于PHPMySQL开发的网址导航系统。该版本是在原有3.8版本的基础上进行了修复和功能增强。我们建议新用户直接使用这个最新版本&#xff0c;放弃旧版本。如果你有二次开发的能力&#xff0c;可以根据更新日志自行进行升级。我们将在后期继续…

论文阅读笔记:RepViT: Revisiting Mobile CNN From Vit Perspective

文章目录 RepViT: Revisiting Mobile CNN From Vit Perspective动机现状问题 贡献实现Block设置独立的token融合器和通道融合器减少膨胀并增加宽度 宏观设计stem的早期卷积简单分类器整体阶段比率 微观设计内核大小选择Squeeze-and-excitation层放置网络架构 实验ImageNet-1K上…

idea import配置

简介 本文记录idea中import相关配置&#xff1a;自动导入依赖、自动删除无用依赖、避免自动导入*包 自动导入依赖 在编辑代码时&#xff0c;当只有一个具有匹配名称的可导入声明时&#xff0c;会自动添加导入 File -> Settings -> Editor -> General -> Auto Imp…

基于xr-frame实现微信小程序的人脸识别3D模型叠加AR功能(含源码)

前言 xr-frame是一套小程序官方提供的XR/3D应用解决方案&#xff0c;基于混合方案实现&#xff0c;性能逼近原生、效果好、易用、强扩展、渐进式、遵循小程序开发标准。xr-frame在基础库v2.32.0开始基本稳定&#xff0c;发布为正式版&#xff0c;但仍有一些功能还在开发&#…