Android Kotlin应用与Python服务端Socket连接超时问题排查
Android Kotlin Socket客户端无法连接Python服务端(超时错误)
问题背景
搭建一套系统,让手机连接至带VPN的服务器,通过Socket实现数据传输、处理存储及回传。服务端用Python编写,客户端是Kotlin开发的Android应用。Python回声服务端已验证可正常运行,但Android客户端连接时出现SocketTimeoutException超时错误。
服务端Python代码
import socket HOST = "10.8.0.1" PORT = 65432 with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind((HOST, PORT)) s.listen() print("Listening...") conn, addr = s.accept() with conn: print(f"Connected by {addr}") while True: data = conn.recv(1024) print(f"Recived: {data.decode(\"utf-8\")}") if not data: break conn.sendall(data)
Android客户端Kotlin代码
package com.example.testsockets import android.os.Bundle import android.view.View import android.widget.TextView import androidx.appcompat.app.AppCompatActivity import com.google.android.material.textfield.TextInputEditText import java.net.InetSocketAddress import java.net.Socket import java.util.concurrent.Executors class MainActivity : AppCompatActivity() { private val socket = Socket() private val executorService = Executors.newSingleThreadExecutor(); override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) } fun send(v: View?){ executorService.execute { var entrada = findViewById<TextInputEditText>(R.id.entrada) var salida = findViewById<TextView>(R.id.salida) val host = "10.8.0.1" val port = 65432 socket.connect(InetSocketAddress(host, port), 3000) // This will be used to send to the server val out = socket.getOutputStream() out.write(entrada.text.toString().toByteArray(charset("UTF-8"))) } } }
AndroidManifest配置
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.INTERNET"/> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.TestSockets" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
错误日志
FATAL EXCEPTION: pool-1-thread-1 Process: com.example.testsockets, PID: 1897 java.lang.Error: java.net.SocketTimeoutException: failed to connect to /10.8.0.1 (port 65432) from /10.8.0.2 (port 45974) after 3000ms at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1173) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:764) Caused by: java.net.SocketTimeoutException: failed to connect to /10.8.0.1 (port 65432) from /10.8.0.2 (port 45974) after 3000ms at libcore.io.IoBridge.connectErrno(IoBridge.java:185) at libcore.io.IoBridge.connect(IoBridge.java:129) at java.net.PlainSocketImpl.socketConnect(PlainSocketImpl.java:137) at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:390) at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:230) at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:212) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:436) at java.net.Socket.connect(Socket.java:621) at com.example.testsockets.MainActivity.send$lambda$0(MainActivity.kt:27) at com.example.testsockets.MainActivity.$r8$lambda$qyWxoPew67mcJ-GNbw1keB5dm7k(Unknown Source:0) at com.example.testsockets.MainActivity$$ExternalSyntheticLambda0.run(Unknown Source:2) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:764)
排查与解决步骤
- 验证网络连通性:在手机上执行
ping 10.8.0.1测试网段连通性,确认手机已成功接入VPN且与服务器在同一网段;在服务器上用nc -zv 10.8.0.1 65432检查端口是否处于监听状态。 - 调整服务端绑定IP:将服务端的
HOST改为0.0.0.0,允许所有网络接口接入,避免因网卡绑定问题导致无法接收连接:HOST = "0.0.0.0" - 修复客户端Socket复用问题:全局Socket实例重复调用
connect会引发异常,改为每次发送时创建新Socket,并添加异常处理与资源释放:fun send(v: View?){ executorService.execute { val entrada = findViewById<TextInputEditText>(R.id.entrada) val salida = findViewById<TextView>(R.id.salida) val host = "10.8.0.1" val port = 65432 val socket = Socket() try { socket.connect(InetSocketAddress(host, port), 3000) val out = socket.getOutputStream() out.write(entrada.text.toString().toByteArray(charset("UTF-8"))) out.flush() out.close() socket.close() runOnUiThread { salida.text = "发送成功" } } catch (e: Exception) { e.printStackTrace() runOnUiThread { salida.text = "连接失败:${e.message}" } } } } - 放行服务器端口:检查服务器防火墙(如
ufw)是否开放65432端口,执行sudo ufw allow 65432/tcp放行;若为云服务器,需在平台安全组添加对应端口的入站规则。 - 确认VPN路由规则:检查Android设备的VPN设置,确保应用被允许通过VPN访问,且VPN已正确路由
10.8.0.0/24网段流量。
内容的提问来源于stack exchange,提问作者Alejandro
相关产品推荐
相关产品推荐

