Android TCP Server 示例

1.添加用户权限

    <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" />

在主窗口的初始化位置添加权限获取代码

var permissions1= arrayOf(
            Manifest.permission.ACCESS_WIFI_STATE,
            Manifest.permission.INTERNET,
            Manifest.permission.ACCESS_NETWORK_STATE,
        )

        if((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_WIFI_STATE) != PackageManager.PERMISSION_GRANTED)||
            (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED)||
            (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED)
            ) {
            ActivityCompat.requestPermissions(this, permissions1,1,)
        } else {
            // 权限已授权,执行相应操作
            Log.d("scoreInfo","权限已授权,执行相应操作2")
        }

2.添加库

添加lifecycle.viewmodel库

3.创建ViewModel供界面调用

import androidx.lifecycle.ViewModel
import androidx.media3.common.util.Log
import androidx.media3.common.util.UnstableApi
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.getAndUpdate
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import java.net.ServerSocket
import java.net.Socket

@androidx.annotation.OptIn(UnstableApi::class)
class TcpServerViewModel: ViewModel() {


    lateinit var tcpServer: TcpServerThread

    init {
        StartTcpServer(3000)
    }

    fun StartTcpServer(port: Int) {
        try {
            tcpServer = TcpServerThread(port)
            tcpServer.start()
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {

        }

    }
}

3.创建TcpServerThread

import androidx.compose.runtime.mutableStateListOf
import java.net.InetAddress
import java.net.ServerSocket
import java.net.Socket
import java.util.concurrent.locks.ReentrantLock

class TcpServerThread(private val port:Int):Thread() {
    val socketList:MutableList<SocketData> = mutableStateListOf()
    private final var lock :ReentrantLock= ReentrantLock()
    override fun run() {
        try{
            val serverSocket = ServerSocket(port)
            println("Server is listening on port $port")
            while (true) {
                val clientSocket: Socket = serverSocket.accept() // 阻塞直到连接建立
                println("New client connected: ${clientSocket.remoteSocketAddress}")

                //查看当前的连接链表,如果有相同的IP,则关闭接收线程,关闭连接。
                for( socketData in socketList){
                    if(socketData.socket.inetAddress.toString() == clientSocket.inetAddress.toString()){
                        var socket = socketData.socket
                        socketData.handler.interrupt()
                        socket.close()
                    }
                }

                val clientThread = ClientHandler(clientSocket,socketList,lock)

                var client = SocketData(clientSocket,clientThread,false,0)
                lock.lock()
                socketList.add(client)
                lock.unlock()

                clientThread.start() // 处理每个客户端连接的新线程

            }
        }
        catch (e:Exception){
            e.printStackTrace()
        }
        finally {

        }

    }

    //添加停止函数
    fun StopServer(){
        lock.lock()
        for(socketData in socketList) {
            socketData.handler.interrupt()
            socketData.socket.close()
        }
        socketList.clear()
        lock.unlock()
    }
}

4.创建ClientHandler

import java.io.BufferedReader
import java.io.InputStreamReader
import java.net.Socket
import java.nio.Buffer

class ClientHandler(private val clientSocket: Socket,var socketList:MutableList<SocketData>,var lock :ReentrantLock ):Thread() {

    override fun run() {
        try {
            val input = clientSocket.getInputStream()
            var buffer = ByteArray(1024)
            var line: String?
            while (true) {
                val readBytes = input.read(buffer)
                if(readBytes<=0)
                {
                    try{
                        sleep(10)
                    }
                    catch(e:Exception)
                    {
                        e.printStackTrace()
                    }
                    break
                }
                else {
                    line = String(buffer.copyOfRange(0,readBytes))
                    println("Received from client: ${line}")
                    

                }//if (line == null || line.isEmpty()) break // 客户端断开连接或无数据时退出循环
                try{
                   sleep(10)
                }
                catch(e:Exception)
                {
                   e.printStackTrace()
                }
            }
        } catch (e: Exception) {
            e.printStackTrace()
        } finally {
            lock.lock()
            try {
                if(socketList.size>0) {
                    for (socketdata in socketList) {
                        if (clientSocket.inetAddress.toString() == socketdata.socket.inetAddress.toString()) {
                            socketList.remove(socketdata)
                        }
                    }
                    Log.d("score", socketList.toString())
                    clientSocket.close() // 关闭套接字连接
                }
            }catch (e: Exception)
            {
                e.printStackTrace()
            }


            lock.unlock()
        }
    }
}

4.添加一些辅助类


import java.net.Socket

data class SocketData (
    var socket: Socket,
    var handler: ClientHandler,
    var RemoveState:Boolean,
    var barid:Int
)

5.调用测试

在compose界面中获取viewmodel变量。

val tcpViewModel = ViewModelProvider(this).get(TcpServerViewModel::class.java)

在界面初始化或按钮点击事件中调用。

tcpViewModel.StartTcpServer(3000)

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lph009

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值