介绍:本文主要介绍在安卓中使用Socket创建服务端和客户端进行通信,服务端可以管理多个客户端连接,完善的异常处理,接口回调,可以满足大部分需求,更多功能自行拓展…
关于Socket套接字:
是网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
使用Socket进行网络通讯的一般步骤如下:
- 创建Socket对象,指定服务器的IP地址和端口号。
- 使用Socket对象的getInputStream()和getOutputStream()方法获取输入输出流,用于接收和发送数据。
- 使用输出流发送请求到服务器,使用输入流读取服务器返回的数据。
- 使用完毕后,通过调用Socket对象的close()方法关闭Socket连接。
创建Socket服务端
功能包括启动服务,关闭连接,发送消息,接收消息,管理客户端,将事件回调给外界等
class SocketServer(private val port: Int, private val listener: SocketServerListener? = null) : Thread() {
private val TAG = "SocketServer"
private lateinit var serverSocket: ServerSocket // serverSocket 对象
private val clientHandlers = mutableListOf<ClientHandler>() // 存储每个客户端线程
private val executor = Executors.newSingleThreadExecutor()
override fun run() {
startServer()
}
// 启动服务器的方法
private fun startServer() {
try {
serverSocket = ServerSocket(port)
Log.i(TAG, "Server is running on port $port")
while (!isInterrupted) {
val clientSocket = serverSocket.accept() // 接受客户端连接
listener?.onClientConnected(clientSocket) // 通知客户端已连接
val clientThread = ClientHandler(clientSocket, listener) // 为每个客户端创建一个新的线程
clientThread.start()
clientHandlers.add(clientThread) // 安全地添加 Handler 到列表
}
} catch (e: Exception) {
listener?.onError(e)
}
}
// 关闭服务器的方法
fun stopServer() {
clientHandlers.forEach { it.closeConnection() } // 关闭所有客户端线程
try {
serverSocket.close() // 关闭 ServerSocket
} catch (e: Exception) {
e.printStackTrace()
}
}
// 当线程被中断时,关闭服务器
override fun interrupt() {
stopServer()
super.interrupt()
}
// 定义处理每个客户端连接的线程
class ClientHandler(private val socket: Socket, private val listener: SocketServerListener? = null) : Thread() {
private var printWriter: PrintWriter? = null
private var bufferedReader: BufferedReader? = null
fun sendMessage(msg: String) {
if (printWriter != null) {
synchronized(printWriter!!) {
printWriter?.println(msg)
}
}
}
override fun run() {
printWriter = PrintWriter(socket.getOutputStream(), true)
bufferedReader = BufferedReader(InputStreamReader(socket.getInputStream()))
try {
var message: String? = null
// 服务端接收数据
while (socket.isConnected && bufferedReader?.readLine()
.also { message = it } != null) {
// 当接收到消息时,通过 listener 通知外部
listener?.onMessageReceived(message!!)
// 回应客户端
//printWriter?.println("Received: $message")
}
} catch (e: IOException) {
listener?.onError(e)
e.printStackTrace()
} finally {
// 确保最后会关闭连接
closeConnection()
}
}
// 关闭连接的方法
fun closeConnection() {
try {
socket.close() // 关闭 socket 连接
printWriter?.close()
bufferedReader?.close()
} catch (e: IOException) {
listener?.onError(e)
}
Log.d("ClientHandler", "Client disconnected ${socket.inetAddress.hostAddress}")
listener?.onClientDisconnected(socket) // 通知外部客户端已断开
}
}
// 发送消息到客户端的方法
fun sendMessage(message: String) {
executor.submit {
clientHandlers.forEach {
it.sendMessage(message)
}
}
}
}
// 定义一个接口,用于接收消息和通知客户端连接和断开
interface SocketServerListener {
fun onMessageReceived(message: String)
fun onClientConnected(client: Socket)
fun onClientDisconnected(client: Socket)
fun onError(e: Exception)
}
创建Socket客户端
功能包括建立连接,关闭连接,发送消息,接收消息,异常处理,将事件回调给外界等
class SocketClient(
private val serverAddress: String,
private val serverPort: Int,
private val listener: SocketClientListener?
) {
private var socket: Socket? = null
private var out: PrintWriter? = null
private var reader: BufferedReader? = null
private val executor = Executors.newSingleThreadExecutor()
private val connectLatch = CountDownLatch(1)
fun connect() {
executor.execute {
try {
socket = Socket(serverAddress, serverPort)
out = PrintWriter(socket!!.getOutputStream(), true)
reader = BufferedReader(InputStreamReader(socket!!.getInputStream()))
listener?.onConnected()
connectLatch.countDown() // 通知已经连接
} catch (e: IOException) {
listener?.onConnectionFailed(e)
}
}
}
fun sendMessage(message: String) {
executor.execute {
connectLatch.await() // 等待连接完成
out?.println(message)
}
}
fun receiveMessages() {
executor.execute {
try {
connectLatch.await() // 等待连接完成
var message: String? = null
while (reader?.readLine().also { message = it } != null) {
listener?.onMessageReceived(message!!)
}
} catch (e: IOException) {
listener?.onError(e)
}
}
}
fun close() {
executor.execute {
try {
// socket 和 reader 关闭顺序不能变,否则会阻塞在 reader?.close()
socket?.close()
reader?.close()
out?.close()
listener?.onDisconnected()
} catch (e: IOException) {
listener?.onError(e)
}
}
}
}
interface SocketClientListener {
fun onConnected()
fun onMessageReceived(message: String)
fun onConnectionFailed(e: Exception)
fun onDisconnected()
fun onError(e: Exception)
}
获取IP地址
public static String getIPAddress() {
try {
List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
for (NetworkInterface intf : interfaces) {
List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
for (InetAddress addr : addrs) {
if (!addr.isLoopbackAddress() && addr instanceof Inet4Address) {
return addr.getHostAddress();
}
}
}
} catch (Exception e) {
Log.e("getIPAddress", e.toString());
}
return "";
}
如何使用
服务端:
val listener = object : SocketServerListener {
override fun onMessageReceived(message: String) {
XLog.i(" SocketServerListener Message received from client: $message")
}
override fun onClientConnected(client: Socket) {
XLog.i(" SocketServerListener Client connected: ${client.inetAddress.hostAddress}")
}
override fun onClientDisconnected(client: Socket) {
XLog.i(" SocketServerListener disconnected: ${client.inetAddress.hostAddress}")
}
override fun onError(e: Exception) {
XLog.i(" SocketServerListener onError: ${e.message}")
}
}
server = SocketServer(12345, listener)
server.start()
客户端:
val client = SocketClient(getIPAddress(), 12345, object : SocketClientListener {
override fun onConnected() {
XLog.i(" SocketClientListener onConnected")
}
override fun onMessageReceived(message: String) {
XLog.i(" SocketClientListener onMessageReceived: $message")
}
override fun onConnectionFailed(e: Exception) {
XLog.i(" SocketClientListener onConnectionFailed: ${e.message}")
}
override fun onDisconnected() {
XLog.i(" SocketClientListener onDisconnected")
}
override fun onError(e: Exception) {
XLog.i(" SocketClientListener onError")
}
})
client.connect()
client.sendMessage("Hello, server!")
client.sendMessage("啊哈哈哈 鸡汤来喽!!!")
client.receiveMessages()
最后
此片文章用来记录学习,方便大家拿来即用,知识点不多,注释已经尽可能详细了,收工,下班!