Kotlin实现TCP/IP客户端如何避免永久等待服务端响应
实现方案
要实现“有数据就处理、没数据就先执行其他任务再轮询检查”的逻辑,不需要让readLine()永久阻塞,最简便的测试场景实现方式是给Socket设置读取超时,配合异常捕获完成轮询判断,同时修正原代码的逻辑错误。
核心修改点
- 给Socket设置
soTimeout读取超时参数:比如设置100ms超时,当调用readLine()超过这个时间还没读到数据,就会抛出SocketTimeoutException,不会永久卡住线程 - 修正原代码的位置错误:原代码把
client1.close()写在了子线程代码块外部,会导致子线程刚启动Socket就被主线程关闭,需要把Socket生命周期管理移到子线程内部 - 增加空值判断:当服务端主动断开连接时,
readLine()会返回null,需要做对应判断避免死循环空转 - 捕获超时异常:触发超时代表当前无可用数据,此时跳转执行其他任务,间隔指定时长后再进入下一轮检查
修改后示例代码
import java.io.BufferedReader import java.io.InputStreamReader import java.io.PrintWriter import java.net.Socket import java.net.SocketTimeoutException import kotlin.concurrent.thread // 原有全局变量保持定义即可 const val SERVER_IP_ADDRESS = "127.0.0.1" const val SERVER_IP_PORT = 8080 var str_user_text = "测试消息" var str_rcvd_data: String? = null fun tcp_client() { thread { val client1 = Socket(SERVER_IP_ADDRESS, SERVER_IP_PORT).apply { // 设置读取超时100ms,可根据实时性要求调整 soTimeout = 100 } // use函数会自动在代码块结束时关闭Socket,避免资源泄漏 client1.use { client -> val output1 = PrintWriter(client.getOutputStream(), true) val input1 = BufferedReader(InputStreamReader(client.inputStream)) while (true) { // 发送逻辑可根据需求调整频率,原逻辑每次循环都发会产生大量重复消息 output1.println(str_user_text) str_rcvd_data = try { input1.readLine() } catch (e: SocketTimeoutException) { // 读取超时,代表当前没有新数据到达 null } if (!str_rcvd_data.isNullOrEmpty()) { // 有服务端数据到达,在这里编写数据处理逻辑 println("收到服务端返回:$str_rcvd_data") } else { // 无可用数据,先执行其他任务 println("当前无新数据,执行其他后台逻辑...") // 间隔300ms后再次检查,间隔时长可按需调整 Thread.sleep(300) } } } } }
补充说明
- 上述方案完全满足测试场景需求,实现简单不需要引入额外依赖;如果要做生产环境可用的客户端,不建议用轮询方案,可以改用Java NIO非阻塞通道或者Kotlin协程,实现更低的资源占用和更高的响应效率
- 超时时间、轮询间隔可以根据实际需求调整:要求响应快就把数值调小,要降低CPU占用就适当增大
- 原循环内每次都发送消息的逻辑建议优化,避免无意义的重复消息发送,可以改成按固定间隔发送、或者待发送内容更新时再触发发送
内容的提问来源于stack exchange,提问作者garrettb
相关产品推荐
相关产品推荐

