• 安卓 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
  • 相关阅读:
    Kaggle比赛:成人人口收入分类
    Hazelcast系列(八):数据结构
    如何防止订单重复支付
    ps提示由于找不到MSVCP140.dll是怎么回事?MSVCP140.dll修复方法
    aws亚马逊云:置以使用 Amazon EC2!!!
    Linux exec函数族
    《计算机视觉中的多视图几何》笔记(7)
    读书笔记:Effective C++ 2.0 版,条款11(拷贝构造函数和赋值操作符)、条款12(初始化列表)
    [React 进阶系列] React Context 案例学习:使用 TS 及 HOC 封装 Context
    结合OD和《植物大战僵尸》,实现随意过关
  • 原文地址:https://blog.csdn.net/WMX843230304WMX/article/details/132637445