如何通过 Kotlin 在 Android 中使用套接字

Posted

技术标签:

【中文标题】如何通过 Kotlin 在 Android 中使用套接字【英文标题】:How to use socket in Android with Kotlin 【发布时间】:2021-06-18 19:10:01 【问题描述】:

我想在 android 中使用 Kotlin 实现一些目标:

如果我单击应用程序上的按钮,应用程序会向 TCP 服务器(我用 python 编写)发送一个字。服务器将返回另一个单词,应用程序将显示一条 toast 消息。

这是我到目前为止所做的,我可以弄清楚发送部分,但我无法让它继续监听套接字以接收来自服务器的消息。

我正在尝试使用协程,但是在网上找到所有资源后,这是我能得到的最好的。

另外,我不确定我是否以正确的方式设置 IP 地址。

提前感谢您的帮助!

'''

class MainActivity : AppCompatActivity() 
override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val sendBtn = findViewById<Button>(R.id.sendBtn )
    val ipBtn = findViewById<Button>(R.id.ipBtn)
    val ipInput = findViewById<TextView>(R.id.ipInput)

    var ipAddress: String = "192.168.0.101"

    // Below is my attempt to keep listening to the socket, if commented, the sending would work. 
    // My guess is the IO thread is caught in the while loop so the other coroutines cannot use 
    // IO thread to send to the server.
    CoroutineScope(IO).launch
        val socket = Socket(ipAddress, 9999)
        var text = ""
        while (true) 
            text = BufferedReader(InputStreamReader(socket.inputStream)).readLine()
            // if text is not null
            // Toast.makeText(this@MainActivity, "Set IP", Toast.LENGTH_SHORT).show()
        
    

    suspend fun sendMessage(message:String)
        val socket = Socket(ipAddress, 9999)
        socket.outputStream.write(message.toByteArray())
        socket.close()
    

    ipBtn.setOnClickListener 
        Toast.makeText(this@MainActivity, "Set IP", Toast.LENGTH_SHORT).show()
        ipAddress = ipInput.text.toString()
    

    sendBtn .setOnClickListener 
        CoroutineScope(IO).launch 
            Log.d("TAG", "message")
            sendMessage("record")
        
    

'''

【问题讨论】:

解决方案可能是使用线程。这是一个很好的(Java)示例:Sending and Receiving Data with Sockets in android @paulsm4 感谢您的建议。我了解到,对于互联网通信,建议使用协程(例如从 API 获取数据)。你能解释一下为什么在我的情况下线程比协程更受欢迎吗? 【参考方案1】:

要从 P2P Fist 发送数据,我们需要一个 Server 和 Client 。在这里,Socket 充当了通过网络发送和接收数据的端点。

    像这样创建一个服务器类
 class ServerClass() :Thread()
       
        lateinit var serverSocket:ServerSocket
        lateinit var inputStream: InputStream
        lateinit var  outputStream: OutputStream
        lateinit var socket: Socket



        override fun run() 
            try 
                serverSocket = ServerSocket(8888)
                socket = serverSocket.accept()
                inputStream =socket.getInputStream()
                outputStream = socket.getOutputStream()
            catch (ex:IOException)
                ex.printStackTrace()
            

            val executors = Executors.newSingleThreadExecutor()
            val handler = Handler(Looper.getMainLooper())
            executors.execute(Runnable
                kotlin.run 
                    val buffer = ByteArray(1024)
                    var byte:Int
                    while (true)
                        try 
                            byte =  inputStream.read(buffer)
                            if(byte > 0)
                                var finalByte = byte
                                handler.post(Runnable
                                    kotlin.run 
                                        var tmpMeassage = String(buffer,0,finalByte)
                                      
                                        Log.i("Server class","$tmpMeassage")
                                    
                                )

                            
                        catch (ex:IOException)
                            ex.printStackTrace()
                        
                    
                
            )
        

        fun write(byteArray: ByteArray)
            try 
                Log.i("Server write","$byteArray sending")
                outputStream.write(byteArray)
            catch (ex:IOException)
                ex.printStackTrace()
            
        
    
    在我们需要传递主机地址的地方创建一个客户端类
class ClientClass(hostAddress: InetAddress): Thread() 
        
         var hostAddress: String = hostAddress.hostAddress
         lateinit var inputStream: InputStream
         lateinit var outputStream: OutputStream
         lateinit var socket: Socket

          fun write(byteArray: ByteArray)
              try 
                  outputStream.write(byteArray)
              catch (ex:IOException)
                  ex.printStackTrace()
              
          

         override fun run() 
             try 
                 socket = Socket()
                 socket.connect(InetSocketAddress(hostAddress,8888),500)
                 inputStream = socket.getInputStream()
                 outputStream = socket.getOutputStream()
             catch (ex:IOException)
                 ex.printStackTrace()
             
             val executor = Executors.newSingleThreadExecutor()
             var handler =Handler(Looper.getMainLooper())

             executor.execute(kotlinx.coroutines.Runnable 
                 kotlin.run 
                     val buffer =ByteArray(1024)
                     var byte:Int
                     while (true)
                         try
                             byte = inputStream.read(buffer)
                             if(byte>0)
                                 val finalBytes = byte
                        handler.post(Runnable
                                     kotlin.run 
                                         val tmpMeassage = String(buffer,0,finalBytes)
                                        
                                         Log.i("client class", tmpMeassage)
                                     
                                 )
                             
                         catch (ex:IOException)
                             ex.printStackTrace()
                         
                     
                 
             )
         

     

确保服务器和客户端端口应该相同,这是双向通信,我们可以在双方传输数据。

【讨论】:

以上是关于如何通过 Kotlin 在 Android 中使用套接字的主要内容,如果未能解决你的问题,请参考以下文章

Android 上的 Kotlin:如何在片段中使用数据库中的 LiveData?

如何在 kotlin android 的活动中访问应用程序类变量

如何通过单击 Image Kotlin Android 来移动 Activity

如何使用 Retrofit Android Kotlin 发布 [重复]

android中通过kotlin使用WebView

如何在 Android Studio 中使用 Kotlin 从 Firestore 数据库中获取下一条和上一条数据?