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

news2024/9/27 12:17:27

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,这里提一下吧

在这里插入图片描述

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

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

相关文章

【后端开发实习】用Nodejs操作mongodb结合Mongoose实现数据库操作

用Nodejs操作mongodb结合Schema实现数据库操作 Mongoose创建Schema定义Schema对象并映射到数据库Model的使用创建文档内容删除文档内容修改文档内容查询文档内容 Document的使用创建并保存将文档对象转换为JSON对象 模块化数据库连接模型初始化 项目部署路由定义后端操作定义启…

19185 01背包问题

解决这个问题的关键是使用动态规划的方法。我们可以创建一个二维数组dp[i][j]&#xff0c;其中i表示考虑前i件物品&#xff0c;j表示背包的容量。dp[i][j]的值表示在考虑前i件物品&#xff0c;且背包容量为j时能获得的最大价值。 ### 算法步骤 1. 初始化一个二维数组dp&#x…

Qt Design Studio 4.5现已发布

Qt Design Studio现已强势回归&#xff0c;生产力和可用性均得到大幅提升。无论是直观的3D编辑界面&#xff0c;还是与Figma和Qt Creator的无缝连接&#xff0c;新版Qt Design Studio将为您带来更好的产品开发体验。快来深入了解Qt Design Studio的全新功能吧&#xff01; 为3…

uniapp实现table排序

根据后端接口传来的数字大小对列表进行升序/降序展示 效果图&#xff0c;价格由高到低降序 价格由低到高 升序 js 降序升序代码如下 export default {data() {return {MtList:[]}},onLoad() {this.MtypeName();//加载列表方法},methods: {MtypeName(){//列表方法this.$api.…

产品经理-一份标准需求文档的8个模块(14)

一份标准优秀的产品需求文档包括&#xff1a; ❑ 封面&#xff1b; ❑ 文档修订记录表&#xff1b; ❑ 目录&#xff1b; ❑ 引言&#xff1b; ❑ 产品概述&#xff1a;产品结构图 ❑ 详细需求说明&#xff1a;产品逻辑图、功能与特性简述列表、交互/视觉设计、需求详细描述&am…

地理信息科学在交通规划中的应用:GIS绘制智慧出行新蓝图

在当代城市化迅猛发展的背景下&#xff0c;交通规划面临着前所未有的挑战与机遇。作为地理信息与遥感领域的研究者&#xff0c;我深感地理信息科学&#xff08;GIS&#xff09;在解决这些问题时扮演着无可替代的角色。本文将深入探讨GIS如何在交通网络分析和优化中发挥核心作用…

netscaler LDAP+RADIUS传统的双因素认证方式(之一)

如果使用传统的双因素认证方式&#xff0c;可以通过在Citrix ADC (NetScaler) 13.1上配置Gateway Virtual Server来实现LDAP和RADIUS的双因素认证。当前配置方式&#xff0c;采用Cateway vServer两个Basic Authtication Policy方式实现&#xff0c;以下是详细步骤&#xff1a; …

蜂窝互联网接入:连接世界的无缝体验

通过Wi—Fi&#xff0c;人们可以方便地接入互联网&#xff0c;但无线局域网的覆盖范围通常只有10&#xff5e;100m。当我们携带笔记本电脑在外面四处移动时&#xff0c;并不是在所有地方都能找到可接入互联网的Wi—Fi热点&#xff0c;这时候蜂窝移动通信系统可以为我们提供广域…

【趣味数学】求阴影部分面积

题 解法1: 中位线法 既然是中点&#xff0c;就可以用起来&#xff0c;横着不行&#xff0c;竖着来&#xff0c;扩展做辅助线 E是中点S&#xff08;AED) 1/4 S(ABCD) 6 做图中辅助延长线&#xff0c;因为E中点&#xff0c;所以S&#xff08;MEB&#xff09;S(AED) 6 同理E也是…

element el-table实现表格动态增加/删除/编辑表格行,带校验规则

本篇文章记录el-table增加一行可编辑的数据列&#xff0c;进行增删改。 1.增加空白行 直接在页面mounted时对form里面的table列表增加一行数据&#xff0c;直接使用push() 方法增加一列数据这个时候也可以设置一些默认值。比如案例里面的 产品件数 。 mounted() {this.$nextTi…

学习通er图和项目思路

ER图 项目构思&#xff1a; 用户功能&#xff1a; 主要功能逻辑&#xff1a;

计算机是如何工作的 (程序猿基础知识)

文章目录 1.计算机的发展史2. 冯诺依曼体系 (Von Neumann Architecture)冯诺依曼简介 (计算机的祖师爷) 3. CPU基本工作流程3.1 逻辑门3.2 门电路(Gate Circuit)3.3 算数逻辑单元 ALU (Arithmetic & Logic Unit)3.3.1 进制的理解3.3.2 算数单元(Arithmetic Unit)3.3.3 逻辑…

【错题集-编程题】买卖股票的最好时机(四)(动态规划)

力扣对应题目链接&#xff1a;188. 买卖股票的最佳时机 IV - 力扣&#xff08;LeetCode&#xff09; 牛客对应题目链接&#xff1a;买卖股票的最好时机(四)_牛客题霸_牛客网 (nowcoder.com) 一、分析题目 1、状态表示 为了更加清晰的区分买入和卖出&#xff0c;我们换成有股…

【从零开始实现stm32无刷电机FOC】【实践】【4/6 stm32高级定时器】

点击查看本文开源的完整FOC工程 在完成理论方面的准备后&#xff0c;是可以进行写代码实现了&#xff0c;但是stm32单片机提供了不少可以用于电机控制的硬件外设&#xff0c;充分利用这些硬件资源&#xff0c;可以减少代码量以及提高运行性能。 本文使用的stm32型号为喜闻乐见的…

天环公益首发原创开发进度网站 带后台

天环公益计划首发原创开发进度网站 带后台 后台地址是&#xff1a;admin.php 后台没有账号密码 这个没有数据库 有能力的可以自己改 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/89520358 更多资源下载&#xff1a;关注我。

位图 、Max Sum、滑动窗口

这篇博客主要总结一下&#xff0c;这两天刷的算法题&#xff1a; 判断字符是否唯一 题目意思很简单不再解读&#xff0c;拿到这道题&#xff0c;其实不难看出哈希表可以直接秒了&#xff0c;注意这是一道面试题&#xff0c;在oj上可以哈希表秒了&#xff0c;如果面试官要求不使…

如何连接到公司的服务器?

1.下载FileZilla FileZilla的下载与安装以及简单使用&#xff08;有图解超简单&#xff09;-CSDN博客 2.打开 3.输入主机 用户名 密码 端口 注&#xff1a;主机支持的协议类型&#xff1a; 4.连接成功 其他方式也有很多&#xff0c;比如通过cmd&#xff0c;html网页等等 3个…

Apache Doris + Apache Hudi 快速搭建指南|Lakehouse 使用手册(一)

作者&#xff1a;SelectDB 技术团队 导读&#xff1a;湖仓一体&#xff08;Data Lakehouse&#xff09;融合了数据仓库的高性能、实时性以及数据湖的低成本、灵活性等优势&#xff0c;帮助用户更加便捷地满足各种数据处理分析的需求。在过去多个版本中&#xff0c;Apache Doris…

下载动画人物

1、网址&#xff1a;动画 2、点击Characters 3、搜索人物 4、点击弹出的人物&#xff0c;弹出对话框选择USE THIS CHARACTER 5、下载 6、点击Animations&#xff0c;搜索walk 7、点击UPLOAD CHARACTER&#xff0c;看到男孩步行&#xff0c;选择In Place&#xff0c;点击下载&…

浅谈后置处理器组件提取器相关的Apply to

浅谈后置处理器组件提取器相关的Apply to 在Apache JMeter中&#xff0c;“提取器”&#xff08;通常指的是正则表达式提取器、JSON路径提取器或CSS/JQuery提取器等&#xff09;是用来从服务器响应中提取信息的重要组件。这些信息可以是cookies、session IDs、特定的文本或者任…