Android 裝置間透過 Socket 通訊,一台當 Server (ServerSocket),多台當 Client (Socket),實現局域網內即時訊息/檔案傳輸。本文提供完整雙端代碼架構與關鍵點。
+----------------+ Wi-Fi Hotspot / LAN +----------------+
| Server 端 | <----------------------------> | Client 端 x N |
| ServerSocket | TCP Socket | Socket |
| accept() 迴圈 | | connect() |
+----------------+ +----------------+
class SocketServer(private val port: Int = 8888) {
private var serverSocket: ServerSocket? = null
private val clients = mutableListOf()
private val executor = Executors.newCachedThreadPool()
fun start() {
executor.execute {
try {
serverSocket = ServerSocket(port)
while (!Thread.currentThread().isInterrupted) {
val client = serverSocket!!.accept() // 阻塞等待連線
clients.add(client)
executor.execute(ClientHandler(client))
}
} catch (e: IOException) { e.printStackTrace() }
}
}
fun broadcast(msg: String) {
clients.forEach { it.outputStream.write(msg.toByteArray()) }
}
inner class ClientHandler(private val socket: Socket) : Runnable {
override fun run() {
try {
val input = socket.inputStream.bufferedReader()
input.forEachLine { line ->
// 處理收到訊息,可再 broadcast 給其他客戶端
handleMessage(line)
}
} catch (e: IOException) { } finally { closeQuietly(socket) }
}
}
fun stop() {
serverSocket?.close()
executor.shutdownNow()
}
}
// AndroidManifest.xml 需權限
//
//
// (開熱點需)
class SocketClient(private val serverIp: String, private val port: Int = 8888) {
private var socket: Socket? = null
private val handler = Handler(Looper.getMainLooper())
fun connect(onConnected: () -> Unit, onMessage: (String) -> Unit, onError: (Exception) -> Unit) {
Thread {
try {
socket = Socket(serverIp, port)
handler.post(onConnected)
val reader = socket!!.inputStream.bufferedReader()
reader.forEachLine { line ->
handler.post { onMessage(line) }
}
} catch (e: Exception) {
handler.post { onError(e) }
}
}.start()
}
fun send(msg: String) {
Thread { socket?.outputStream?.write("$msg\n".toByteArray()) }.start()
}
fun disconnect() { socket?.close() }
}
| 議題 | 解決方案 |
|---|---|
| 手機開熱點 | WifiManager.setWifiApEnabled(null, true) (需系統簽名/Root) 或引導使用者手動開啟「攜帶式熱點」 |
| 發現 Server IP | 固定熱點 IP (通常 192.168.43.1) / UDP 廣播發現 / mDNS (Bonjour) / QR Code 掃描 IP |
| 斷線重連 | Client 端實作指數退避重連邏輯,Server 端定期心跳檢測清理死連線 |
| 大檔案傳輸 | 分塊發送 + 校驗和 (CRC32/MD5) + 斷點續傳 (RandomAccessFile) |
| 編碼統一 | 協議層統一 UTF-8,訊息以換行符 `\n` 或長度前綴分幀 |
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 掃描/連接 Wi-Fi Direct 需定位權限 -->
<uses-permission android:name="android.permission.NEARBY_WIFI_DEVICES" />
<!-- Android 13+ 專用 -->
提問者回饋:「Android的socket不就是java的socket麼,比如說應用什麼快傳就是開wifi熱點然後用socket啊」。掌握 Java Socket 基礎,結合 Android 生命週期管理與權限配置,即可實作穩定的裝置間通訊。