• 安卓 tcp 客户端


    安卓 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()
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112

    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)
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87

    activity_main.xml

    
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110

    AndroidManifest.xml 配置清单

    
    <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>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    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'
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    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
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
  • 相关阅读:
    BI大屏可视化开发源码,Java+Netcore大屏源码,大屏开发
    io多路复用:select、poll和epoll
    Docker镜像的保存,打包,导入,运行
    【FPGA教程案例64】硬件开发板调试4——通过vio扩充ila数据采集种类
    尝试用Unity还原蔚蓝(Celeste)—— 真·操控、移动、手感篇
    机器学习笔记 - 时间序列预测研究:法国香槟的月销量
    Ubuntu 22.10 UEFI 引导安装在第二块硬盘
    本地部署 streaming-llm
    SaaSBase:什么是有道云笔记?
    2022年鲜为人知的CSS 特性了解起来~
  • 原文地址:https://blog.csdn.net/WMX843230304WMX/article/details/132637445