安卓 tcp 客户端

news2024/11/16 11:56:06

安卓 tcp 客户端

Server:8888 是Qt 写的Tcp 服务器 ip 是 192.168.2.103 port是8888
安卓手机运行 kotlin 语法的Tcp Client ,连接,收发数据
效果如下图

在这里插入图片描述

Tcpclient

package com.example.myapplication

import android.os.Handler
import android.os.Looper
import android.util.Log
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.InputStreamReader
import java.io.OutputStreamWriter
import java.net.Socket

class TcpClient(private val ipAddress: String, private val port: Int) {
    private lateinit var socket: Socket
    private lateinit var reader: BufferedReader
    private lateinit var writer: BufferedWriter

    // 接收线程
    private val messageReceiverThread = Thread {
        //主消息处理器,用于向外部发送tcp收到的数据
        val handler = Handler(Looper.getMainLooper())

        val buffer = StringBuilder()
        val charBuffer = CharArray(1024) // 调整缓冲区大小

        while (!Thread.currentThread().isInterrupted) {
            try {
//                val receivedData = reader.readLine() ?: ""
//                Log.d("TcpClient",receivedData)
//                handler.post {
//                    onDataReceived(receivedData)
//                }
                val bytesRead = reader.read(charBuffer)
                if (bytesRead == -1) {
                    // 如果没有更多数据可读,则退出循环
                    Log.d("TcpClient","continue")
                    continue
                }
                // 清空缓冲区
                buffer.clear()
                // 将读取的数据追加到缓冲区
                buffer.append(charBuffer, 0, bytesRead)
                // 通知UI线程更新UI
                handler.post {
                    Log.d("TcpClient","buffer : "+buffer.toString())
                    onDataReceived(buffer.toString())
                }

            } catch (e: Exception) {
                Log.e("TcpClient","Exception")
                e.printStackTrace()
                break
            }
        }
    }


    // 外部调用,定义数据接收监听器接口
    interface DataReceivedListener {
        fun onDataReceived(data: String)
    }

    private var dataReceivedListener: DataReceivedListener? = null

    // 外部调用,设置数据接收监听器
    fun setDataReceivedListener(listener: DataReceivedListener) {
        dataReceivedListener = listener
    }

    // 通知数据接收事件
    private fun onDataReceived(data: String) {
        dataReceivedListener?.onDataReceived(data)
    }

    // 1
    fun connectToServer() {
        try {
            socket = Socket(ipAddress, port)
            reader = BufferedReader(InputStreamReader(socket.getInputStream()))
            writer = BufferedWriter(OutputStreamWriter(socket.getOutputStream()))
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    fun sendMessage(message: String) {
        try {
            writer.write(message)
//            writer.newLine()
            writer.flush()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    // 2
    fun startMessageReceiver() {
        messageReceiverThread.start()
    }

    fun stopMessageReceiver() {
        messageReceiverThread.interrupt()
    }

    fun close() {
        try {
            socket.close()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

MainActivity

package com.example.myapplication


import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.text.Editable
import android.util.Log
import android.widget.Button
import android.widget.EditText
import android.widget.TextView

class MainActivity : AppCompatActivity() {
    private lateinit var ipAddress: String
    private var port: Int = 0
    private lateinit var recvText: EditText
    private lateinit var tcpClient: TcpClient

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        recvText = findViewById(R.id.recvText)

        // start tcp
        val startButton: Button = findViewById(R.id.startBtn)
        // 设置按钮点击事件
        startButton.setOnClickListener {
            // 设置IP地址和端口(请根据需要修改)
            ipAddress = findViewById<EditText?>(R.id.ipText).text.toString()
            port = findViewById<EditText?>(R.id.portNum).text.toString().toInt()
            // 创建TcpClient实例
            tcpClient = TcpClient(ipAddress, port)
            // 设置数据接收监听器
            tcpClient.setDataReceivedListener(object : TcpClient.DataReceivedListener {
                override fun onDataReceived(data: String) {
                    // 在数据接收回调中更新UI
                    updateUI(data)
                }
            })


            // 在新线程中执行连接操作
            Thread {
                tcpClient.connectToServer()
                tcpClient.startMessageReceiver()
            }.start()
        }
        // stop tcp
        val stopBtn: Button = findViewById(R.id.stopBtn)
        stopBtn.setOnClickListener {
            Thread {
                tcpClient.stopMessageReceiver()
                tcpClient.close()
            }.start()
        }

        // send on thread
        val sendBtn: Button = findViewById(R.id.sendBtn)
        sendBtn.setOnClickListener {
            Thread {
                var sendText : EditText= findViewById(R.id.sendText)
                tcpClient.sendMessage(sendText.text.toString())
            }.start()
        }

        var cleanBtn:Button = findViewById(R.id.cleanBtn)
        cleanBtn.setOnClickListener {
            recvText.text.clear()
        }

    }


    private fun updateUI(data: String) {
        Log.d("MainActivity","data:"+data)
        val editableText = Editable.Factory.getInstance().newEditable(data)
        recvText.text?.append(editableText)
    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:id="@+id/linearLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">


    <LinearLayout
        android:layout_width="406dp"
        android:layout_height="53dp"
        android:orientation="horizontal">

        <EditText
            android:id="@+id/ipText"
            android:layout_width="204dp"
            android:layout_height="47dp"
            android:layout_weight="4"
            android:ems="10"
            android:inputType="text"
            android:text="192.168.2.103" />

        <EditText
            android:id="@+id/portNum"
            android:layout_width="204dp"
            android:layout_height="45dp"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="number"
            android:text="8888" />
    </LinearLayout>

    <LinearLayout
        android:layout_width="409dp"
        android:layout_height="55dp"
        android:orientation="horizontal">

        <Button
            android:id="@+id/startBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="start" />

        <Button
            android:id="@+id/stopBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="stop" />

        <Space
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1" />

    </LinearLayout>

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="send data"
        android:textSize="20sp" />

    <EditText
        android:id="@+id/sendText"
        android:layout_width="match_parent"
        android:layout_height="148dp"
        android:layout_weight="4"
        android:ems="10"
        android:gravity="start|top"
        android:inputType="textMultiLine" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/sendBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="send" />

        <Button
            android:id="@+id/cleanBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="clean recv" />
    </LinearLayout>

    <TextView
        android:id="@+id/textView3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="recv data"
        android:textSize="20sp" />

    <EditText
        android:id="@+id/recvText"
        android:layout_width="match_parent"
        android:layout_height="202dp"
        android:layout_weight="4"
        android:ems="10"
        android:gravity="start|top"
        android:inputType="textMultiLine" />

</LinearLayout>

AndroidManifest.xml 配置清单

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapplication">

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


    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.MyApplication">

        <activity
            android:name=".MainActivity"
            android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>


    </application>

</manifest>

build.gradle (app)

plugins {
    id 'com.android.application'
    id 'org.jetbrains.kotlin.android'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.myapplication"
        minSdkVersion 28
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {

    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.2.1'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

build.gradle (my proj )

使用国内镜像

// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        maven { url 'https://maven.aliyun.com/repository/google' }
        maven { url 'https://maven.aliyun.com/repository/jcenter' }
        maven { url 'https://maven.aliyun.com/repository/public' }
        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
//        google()
//        mavenCentral()
    }
    dependencies {
        classpath "com.android.tools.build:gradle:4.2.1"
        classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.0'

        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        maven { url 'https://maven.aliyun.com/repository/google' }
        maven { url 'https://maven.aliyun.com/repository/jcenter' }
        maven { url 'https://maven.aliyun.com/repository/public' }
        maven { url 'https://maven.aliyun.com/repository/gradle-plugin' }
//        google()
//        mavenCentral()
//        jcenter() // Warning: this repository is going to shut down soon
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

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

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

相关文章

Xilinx UltraScale架构之可配置逻辑块CLB

目录 一、概览 二、UltraScale架构 2.1 UltraScale/UltraScale特点 2.2 与7系列CLB差异 三、 CLB结构 3.1 LUT 3.2 FF 3.3 多路选择器Multiplexers 3.4 进位链Carry Chain 四、应用 4.1 分布式RAM 4.2 移位寄存器 4.3 进位链Carry Chain 五、参考资料 一、概览 二…

CSDN新手流量劵使用教程CSDN新手攻略2023:流量劵使用教程与30天打卡创作福利一步到位

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

轻松提取视频画面,一秒变序列图片,让精彩瞬间永恒留存!

你是否曾经想要保存视频中的某个精彩瞬间&#xff0c;或者需要将视频转换为一系列图片以便于编辑或研究&#xff1f;现在&#xff0c;我们为你提供了一种快速、简单的方法&#xff0c;让你轻松提取视频画面&#xff0c;一秒变序列图片&#xff01; 首先第一步&#xff0c;我们…

【K8S系列】深入解析k8s网络插件—Cilium

序言 做一件事并不难&#xff0c;难的是在于坚持。坚持一下也不难&#xff0c;难的是坚持到底。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记论点蓝色&#xff1a;用来标记论点 在现代容器化应用程序的世界中…

BuhoCleaner for mac:让你的Mac重获新生

你是否曾经因为电脑运行缓慢而感到困扰&#xff1f;是否曾经因为大量的垃圾文件和无效的临时文件而感到头疼&#xff1f;如果你有这样的烦恼&#xff0c;那么BuhoCleaner for mac就是你的救星&#xff01; BuhoCleaner for mac是一款专门为Mac用户设计的系统清理工具&#xff…

刷完这个面试笔记,18K真的不能再少了....

大家好&#xff0c;最近有不少小伙伴在后台留言&#xff0c;得准备面试了&#xff0c;又不知道从何下手&#xff01;为了帮大家节约时间&#xff0c;特意准备了一份面试相关的资料&#xff0c;内容非常的全面&#xff0c;真的可以好好补一补&#xff0c;希望大家在都能拿到理想…

sftp传输文件

sftp传输文件 有时只能通过命令行传输文件&#xff0c;使用sftp命令也很方便&#xff0c;sftp基于SSH协议&#xff0c;可以使用ssh的配置文件 关于ssh的配置文件可以参考ssh常用操作 sftp连接服务器 常规使用方式 sftp 服务器用户名服务器地址 # 回车输入密码 在不使用ss…

Axure RP仿QQ音乐app高保真原型图交互模板源文件

Axure RP仿QQ音乐app高保真原型图交互模板源文件。本套素材模板的机型选择华为的mate30&#xff0c;在尺寸和风格方面&#xff0c;采用标准化制作方案&#xff0c;这样做出来的原型图模板显示效果非常优秀。 原型中使用大量的动态面板、中继器、母版&#xff0c;涵盖Axure中技…

FL Studio21.2中文版下载激活图文教程

FL Studio21.1是一款经典的DAW&#xff08;数位音讯工作站&#xff09;软件。知名音乐资讯网站Music Radar 每年都会针对音乐领域相关产品&#xff0c;推出各类最佳产品及服务排名。在最新公布的2022 年最佳DAW 软件榜单中&#xff0c; FL Studio在电子音乐制作方面的强大优势&…

在线音乐播放器测试报告

文章目录 一、项目背景二、项目功能三、测试目的四、测试环境五、测试计划5.1 功能测试5.2 自动化测试 六、测试结果 一、项目背景 今天&#xff0c;市面上的音乐播放器种类繁多同时功能强大。一个单纯的音乐播放器可能不再单纯只是音乐播放的功能&#xff0c;而是更多地集短视…

【项目设计】高并发内存池(Concurrent Memory Pool)

目录 1️⃣项目介绍 &#x1f359;项目概述 &#x1f359;知识储备 2️⃣内存池介绍 &#x1f359;池化技术 &#x1f359;内存池 &#x1f359;内存池主要解决的问题 &#x1f365;内碎片 &#x1f365;外碎片 &#x1f359;malloc 3️⃣ 定长内存池设计 4️⃣ 项…

区块链实验室(20) - FISCO控制台连接到指定的节点

在FISCO技术文档中&#xff0c;控制台默认采用config.toml作为配置文件&#xff0c;并指定了连接的节点地址和商品&#xff0c;如下所示。 [network] peers["127.0.0.1:20200", "127.0.0.1:20201"] # The peer list to connect在该案例中&#xff0c;控…

音频——I2S 标准模式(二)

I2S 基本概念飞利浦(I2S)标准模式左(MSB)对齐标准模式右(LSB)对齐标准模式DSP 模式TDM 模式 文章目录 I2S format时序图逻辑分析仪抓包 I2S format 飞利浦 (I2S) 标准模式 数据在跟随 LRCLK 传输的 BCLK 的第二个上升沿时传输 MSB&#xff0c;其他位一直到 LSB 按顺序传传输依…

【方案】基于安防监控视频/智能分析网关AI识别技术的防溺水监管

溺水是造成许多人死亡的主要原因之一。无论是在游泳池、河流、湖泊还是海洋中&#xff0c;溺水都可能导致人们失去生命。即使没有造成死亡&#xff0c;溺水所引发的窒息和水下活动中的创伤等伤害&#xff0c;有可能引起长期甚至永久性的身体损伤&#xff0c;对个人和家庭造成巨…

Python入门学习——Day2-控制流程

一、Python 控制流程 什么是控制流程&#xff1a; 在Python中&#xff0c;控制流程指的是根据不同的条件或规则来控制程序的执行顺序和逻辑。Python提供了多种控制流程的语句和结构&#xff0c;可以根据条件进行分支判断和循环迭代。 1.1 条件语句&#xff08;if-elif-else&…

PY32F003F18P单片机概述

PY32F003F18P单片机是普冉的一款ARM微控制器&#xff0c;内核是Cortex-M0。这个单片机的特色&#xff0c;就是价格便宜&#xff0c;FLASH和SRAM远远超过8位单片机&#xff0c;市场竞争力很强大。 一、硬件资源&#xff1a; 1)、FLASH为64K字节&#xff1b; 2)、SRAM为8K字节&…

CAD图纸加密软件——公司核心文件数据防泄密「天锐绿盾」

PC访问地址&#xff1a; isite.baidu.com/site/wjz012xr/2eae091d-1b97-4276-90bc-6757c5dfedee 数据安全保护系统 数据安全保护系统以全面数据文件安全策略、加解密技术与强制访问控制有机结合为设计思想&#xff0c;对信息媒介上的各种数据资产&#xff0c;实施不同安全等级…

一份优秀的接口自动化测试方案是啥样的?

1、引言 1.1 文档版本 1.2 项目情况 1.3 文档目的 本文档主要用于指导XXX-YY项目常用接口自动化测试工作的开展。本文档的主要目的在于提供项目接口自动化测试的技术方案、实施方案和计划方案等。 2、接口自动化实施目标 2.1 实施原则 XXX-YY项目采用接口自动化测试&#xff0…

云备份——实用类工具实现

一&#xff0c;文件实用类设计实现 不管是客户端还是服务端&#xff0c;文件的传输备份都涉及到文件的读写&#xff0c;包括数据管理信息的持久化也是如此&#xff0c;因此首先设计封装文件操作类&#xff0c;这个类封装完毕之后&#xff0c;则在任意模块中对文件进行操作时都将…

SpringCloudAlibaba OpenFeign整合及详解

SpringCloudAlibaba OpenFeign 在前面&#xff0c;我们使用Nacos服务注册发现后&#xff0c;服务远程调用可以使用RestTemplateRibbon或者OpenFeign调用。实际开发中很少使用RestTemplate这种方式进行调用服务&#xff0c;每次调用需要填写地址&#xff0c;还要配置各种的参数&…