Android之间互传消息之ServerSocket,Android服务端接收Socket发送的TCP

Android之间在在局域网下互传消息,咱就不用走云服务器了吧,让俩安卓设备,自己传呗

方式1 通过在安卓设备上搭建Web服务器接收数据,可参考

Android使用AndServer在安卓设备上搭建服务端(Java)(Kotlin)两种写法

方式2 本文章,搭建Socket服务器,接收数据,发送TCP

此类文章网上一大堆,不多做讲解,直接上代码,自行参考

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7001495969ce4b6fad6cc4131605e174.png

清单文件中添加权限

在这里插入图片描述

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

MainActivity

class MainActivity : AppCompatActivity() {

    var mBinding: ActivityMainBinding? = null

    var timer: Timer? = null

    var mSocket: Socket? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        this.window.statusBarColor = this.resources.getColor(R.color.white)
        this.window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR

        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        requestPermission()

        mBinding!!.tv1.setOnClickListener {
            val intent = Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)
            startActivity(intent)

        }
    }

    override fun onResume() {
        super.onResume()
        if (mSocket != null){
            mSocket!!.close()
            mSocket = null
        }
        initServer()



        //定时器
        if (timer != null){
            timer!!.cancel()
            timer = null
        }
        timer = Timer()
        val timerTask: TimerTask = object : TimerTask() {
            override fun run() {
                runOnUiThread {
                    //每次刷新再次操作
                    //加个定时器,动态获取ip地址
                    mBinding!!.tv1.text = "本机IP:${getLocalIpAddress()},端口号: 8020"
                }
            }
        }
        timer?.schedule(timerTask, 0, 1000) //开启刷新,第二个参数是多长时间之后开始倒计时,第三个参数是多长时间进行一次
    }

    private fun initServer(){
        object : Thread() {
            override fun run() {
                try {
                    // 创建ServerSocket   E5 93 88 E5 93 88 E5 93 88 E5 93 88 0A
                    val serverSocket = ServerSocket(8020)
                    Log.e("TAG","32131232321--开启服务器,监听端口 9569--" + getLocalIpAddress())
                    // 监听端口,等待客户端连接
                    while (true) {
                        Log.e("TAG","32131232321--等待客户端连接--")
                        mSocket = serverSocket.accept() //等待客户端连接
                        Log.e("TAG","32131232321---得到客户端连接:$mSocket")
                        mBinding!!.tv2.post {
                            mBinding!!.tv2.text = "当前连接IP:${mSocket}"
                        }

                        startReader(mSocket!!)
                    }
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }.start()
    }

    // 获取ip地址
    private fun getLocalIpAddress(): String? {
        val netManager =
            applicationContext.getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
        val info = netManager.activeNetworkInfo

        // 网络是否连接
        return if (info != null && info.isConnected) {
            // wifi类型
            if (info.type == ConnectivityManager.TYPE_WIFI) {
                getWifiIpAddress()
            } else {
                // 其他类型
                getEthIpAddress()
            }
        } else "0.0.0.0"
    }


    // 获取有线网络的ip4地址
    private fun getEthIpAddress(): String? {
        val infaceName = "eth0"
        val ip = "0.0.0.0"
        try {
            val netInterface: Enumeration<NetworkInterface> =
                NetworkInterface.getNetworkInterfaces()
            while (netInterface.hasMoreElements()) {
                val inface: NetworkInterface = netInterface.nextElement()
                if (!inface.isUp()) {
                    continue
                }

                // eth0 有线网络判断
                if (infaceName != inface.getDisplayName()) {
                    continue
                }
                val netAddressList: Enumeration<InetAddress> = inface.getInetAddresses()
                while (netAddressList.hasMoreElements()) {
                    val inetAddress: InetAddress = netAddressList.nextElement()
                    // 获取IP4地址
                    if (inetAddress is Inet4Address) {
                        return inetAddress.getHostAddress()
                    }
                }
            }
        } catch (e: Exception) {
        }
        return ip
    }



    // 获取wifi的ip地址
    private fun getWifiIpAddress(): String? {
        val wifiManager = applicationContext.getSystemService(WIFI_SERVICE) as WifiManager
        val wifiInfo = wifiManager.connectionInfo

        // 获取32位整型IP地址
        val ipAddress = wifiInfo.ipAddress

        //返回整型地址转换成“*.*.*.*”地址
        return String.format(
            "%d.%d.%d.%d",
            ipAddress and 0xff, ipAddress shr 8 and 0xff,
            ipAddress shr 16 and 0xff, ipAddress shr 24 and 0xff
        )
    }

    /**
     * 从参数的Socket里获取消息
     */
    private fun startReader(mSocket: Socket) {
        object : Thread() {
            override fun run() {
                try {
                    // 获取读取流
                    val ins = mSocket.getInputStream()
                    val buf = ByteArray(32)
                    //获取数据赋值
                    while (ins.read(buf) > 0) {
                        //收到客户端发送的数据之后再发
                        //serverSendMessage(getAppData())

                        mBinding!!.tvId.post {
                            var mS = mBinding!!.tvId.text.toString();
                            mS += String(buf)
                            mBinding!!.tvId.text = mS

                            setML(String(buf))

                        }
                        /*if (buf != null) {
                            //延迟销毁
                            runOnUiThread {
                                Handler().postDelayed({
                                    ins.close()
                                    if (mSocket != null){
                                        mSocket.close()
                                    }
                                }, 3000)
                            }

                        }*/
                    }
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }.start()
        /*object : Thread() {
            override fun run() {
                try {
                    // 获取读取流
                    val mIn = BufferedReader(InputStreamReader(mSocket.getInputStream(), "utf-8"))
                    var line = ""
                    Log.e("TAG","32131232321---*等待客户端输入---13132321*---")
                    while (mIn.readLine().also { line = it } != null) { // 读取数据
                        Log.e("TAG","32131232321---*等待客户端输入*")
                        Log.e("TAG","32131232321----获取到客户端的信息:$line")
                    }
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }.start()*/
    }

    //通过socket来给客户端发送消息
    private fun serverSendMessage(mServerSendMessage: String) {
        object : Thread() {
            override fun run() {
                val out: PrintWriter
                try {
                    out = PrintWriter(
                        BufferedWriter(OutputStreamWriter(mSocket!!.getOutputStream())),
                        true
                    )
                    Log.e("TAG","32131232321---发送给客户数据*---" + mServerSendMessage)
                    out.println(mServerSendMessage)
                } catch (e: IOException) {
                    e.printStackTrace()
                }
            }
        }.start()
    }

    /*动态申请权限操作*/
    private var isPermissionRequested = false
    private fun requestPermission() {
        if (Build.VERSION.SDK_INT >= 23 && !isPermissionRequested) {
            isPermissionRequested = true
            val permissionsList: ArrayList<String> = ArrayList()
            val permissions = arrayOf<String>(
                //在这里加入你要使用的权限
                Manifest.permission.READ_CONTACTS,
                Manifest.permission.ACCESS_COARSE_LOCATION,
                Manifest.permission.READ_CALENDAR,
                Manifest.permission.ACCESS_FINE_LOCATION,
                Manifest.permission.WRITE_CONTACTS,
                Manifest.permission.ACCESS_WIFI_STATE,
            )
            for (perm in permissions) {
                if (PackageManager.PERMISSION_GRANTED != checkSelfPermission(perm)) {
                    permissionsList.add(perm)
                    // 进入这里代表没有权限.
                }
            }
            if (permissionsList.isNotEmpty()) {
                val strings = arrayOfNulls<String>(permissionsList.size)
                requestPermissions(permissionsList.toArray(strings), 0)
            }
        }
    }

    //单独处理命令
    private fun setML(ml: String){
        if (ml.contains("xc")){
            val intent = Intent(Intent.ACTION_PICK)
            //指定获取的是图片
            intent.type = "image/*"
            startActivityForResult(intent,10086)
        }
        if (ml.contains("qc")){
            mBinding!!.tvId.post {
                mBinding!!.tvId.text = ""
            }
        }

    }


}

activity_main

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>

    </data>

    <androidx.appcompat.widget.LinearLayoutCompat
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <TextView
            android:id="@+id/tv1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:textColor="#000000"
            android:text="本机IP"/>

        <TextView
            android:id="@+id/tv2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:textSize="16sp"
            android:layout_marginTop="10dp"
            android:textColor="#000000"
            android:text="未连接"/>

        <TextView
            android:id="@+id/tv_id"
            android:layout_marginTop="10dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </androidx.appcompat.widget.LinearLayoutCompat>
</layout>

因为用到了 DataBind,这里提一下吧

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

空安全编程的典范:Java 8中的安全应用指南

文章目录 一、Base64 编码解码1.1 基本的编码和解码1.2 URL 和文件名安全的编码解码器1.3 MIME Base64编码和解码 二、Optional类三、Nashorn JavaScript 一、Base64 编码解码 1.1 基本的编码和解码 Base64 编码&#xff1a; 使用 Base64.getEncoder().encodeToString(origin…

【STM32嵌入式系统设计与开发---拓展】——1_8_寄存器的理解

1、寄存器的理解 &#xff08;1&#xff09;MOS管 MOS管是一种场效应晶体管&#xff0c;通过控制栅极电压来调节漏极和源极之间的电流&#xff0c;常用于电子开关和放大器电路中。 MOS管就像是电子开关&#xff0c;可以通过控制一个小电压来打开或关闭一个大电流&#xff0c;常…

小程序-1(项目结构+代码结构+宿主环境+组件)

目录 1.小程序简介 2.小程序的项目结构 小程序的基本组成结构 小程序的页面组成部分 json配置文件的作用 app.json文件 project.config.json文件 sitemap.json文件 页面的.json文件 新建小程序页面 修改项目首页 3.小程序的代码结构 wxml和html的区别 wxss和css的…

数据结构(Java):LinkedList集合Stack集合

1、集合类LinkedList 1.1 什么是LinkedList LinkedList的底层是一个双向链表的结构&#xff08;故不支持随机访问&#xff09;&#xff1a; 在LinkedList中&#xff0c;定义了first和last&#xff0c;分别指向链表的首节点和尾结点。 每个节点中有一个成员用来存储数据&…

postgresql简单导出数据与手动本地恢复(小型数据库)

问题 需要每天手动备份postgresql。 步骤 导出数据 /opt/homebrew/opt/postgresql16/bin/pg_dump --file/Users/zhangyalin/backup_sql/<IP地址>_pg-2024_07_15_17_30_15-dump.sql --dbname<数据库名> --username<用户名> --host<IP地址> --port54…

Python array的特点及使用

1、Python array的特点及使用 1.1、python array为什么只能接收指定类型数据 array 模块提供了一种叫做 array 的数据结构&#xff0c;它表示一块连续的内存空间&#xff0c;所有的元素必须是相同的类型。这是因为在内存中&#xff0c;数组元素存储在连续的位置上&#xff0c…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 游乐园门票 (200分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; 最新华为O…

数据结构java笔记

线性表 数组 物理地址连续、逻辑地址连续。数组长度是固定的&#xff0c;不能动态增长或缩小&#xff0c;数组中元素的类型相同&#xff08;适合用于元素个数固定&#xff0c;且快速用下标访问&#xff09; ArrayList&#xff08;动态数组&#xff09; 物理地址连续、逻辑地…

【C++练级之路】【Lv.26】类型转换

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《算法神殿》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 一、C风格类型转换1.1 隐式类型转换1.2 显式类型转换 二、C风格类型转换2.1 static_cast2.2 dynamic_cast2.3…

【C++】—— 初识C++

【C】—— 初识C 一、什么是 C二、C 的发展历史三、C 版本更新四、C 的重要性五、C 在工作领域中的运用六、C 书籍推荐&#xff1a; 一、什么是 C C语言 是结构化和模块化的语言&#xff0c;适合处理较小规模的程序。对于复杂的问题&#xff0c;规模较大的程序&#xff0c;需要…

【eNSP模拟实验】单臂路由实现VLAN间通信

实验需求 如下图所示&#xff0c;辅导员办公室需要访问处在不同vlan的学生管理服务器的文件&#xff0c;那么如何实现两台终端相互通信呢&#xff1f;我们可以使用单臂路由的方式来实现。 单臂路由&#xff08;router-on-a-stick&#xff09;是指在路由器的一个接口上通过配置…

小型医疗门诊挂号收费后台系统源码 医院管理系统后台thinkphp内核源码(带微信登录)

源码简介&#xff1a; 好用的小型医疗门诊后台管理系统的源码&#xff0c;就是那种医院管理用的&#xff0c;核心是用thinkphp做的。这个系统源码啊&#xff0c;功能多&#xff0c;用起来也方便。它还支持第三方配置和微信登录。 这玩意儿是基于ThinkPHP搞出来的医疗门诊系统…

AJAX知识点(详解)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 非常期待和您一起在这个小…

Flowable-流程图标与流程演示

BPMN 2.0是业务流程建模符号2.0的缩写。它由Business Process Management Initiative这个非营利协会创建并不断发展。作为一种标识&#xff0c;BPMN 2.0是使用一些符号来明确业务流程设计流程图的一整套符号规范&#xff0c;它能增进业务建模时的沟通效率。目前BPMN2.0是最新的…

持续集成01--Git版本管理及基础应用实践

前言 本系列文章旨在深入探讨持续集成/持续部署&#xff08;Continuous Integration/Continuous Deployment, CI/CD&#xff09;流程中的各个环节&#xff0c;而本篇将聚焦于Git版本管理及其基本应用。通过本文&#xff0c;读者将了解到Git的基本原理、安装配置、基本命令以及如…

高校动作捕捉与数字人开发实训室方案:助推高校开设虚拟数字人微专业

目前一些学校除了传统的实训室建设之外&#xff0c;部分院校会建设一些“微专业”&#xff0c;专业方向与AIGC以及虚拟数字人有关&#xff0c;通过引进一些虚拟数字人以及全身动作捕捉设备相关的产品和系统工具&#xff0c;进行设计课程方案&#xff0c;比如虚拟人直播&#xf…

Vue3学习体验(一)

搭建工程 使用vue-cli脚手架创建vue3工程 vue create vue3-app-vue-cliVue-cli官网&#xff1a;https://cli.vuejs.org/zh/guide/installation.html 使用vite搭建vue3工程 npm init表示临时的下载vite应用来创建vue3工程&#xff0c;工程名称为vue3-app-vite npm init vit…

银河麒麟高级服务器操作系统V10加固操作指南

1:检查系统openssh安全配置: 2:检查是否设置口令过期前警告天数: 3:检查账户认证失败次数限制: 修改/etc/pam.d/system-auth文件中deny的参数即可 4:检查是否配置SSH方式账户认证失败次数限制:

SAP DR创建借项凭证简介

DR创建借项凭证简介 创建借项凭证请求的详细步骤1. 进入创建销售订单的界面2. 选择销售凭证类型3. 输入销售组织数据4. 输入客户和参考数据5. 添加项目明细6. 检查和保存创建实际的借项凭证借项凭证后台配置定义凭证类型定义项目类别定义销售开票类型借项凭证请求的业务意义跟踪…

@RequestBody注解的使用及源码解析

前言 RequestBody 注解是我们进行JavaEE开发&#xff0c;最常见的几个注解之一&#xff0c;这篇博文我们以案例和源码相结合&#xff0c;帮助大家更好的了解 RequestBody 注解 使用案例 1.自定义实体类 Data NoArgsConstructor AllArgsConstructor public class User {priv…