Kotlin中的WebSocket通信

WebSocket通信是非常常见的,基于TCP通信的一种方式。接下来将了解集中,在kotlin中实现WebSocket通信的方案

Java-WebSocket

Java-WebSocket是一个独立于Spring体系之外,可以独立运行的WebSocket构建工具。它包含了服务端与客户端。

  • 服务端:提供WebSocket的链接服务,处理消息,回复消息,广播消息,实现消息中转。一个服务端可以被多个客户端链接。
  • 客户端:链接服务端的客户端,连接到服务到之后可以接收和处理来自服务端的消息,基于服务端做实时通讯。
    要使用Java-WebSocket,需要引入以下依赖:
<dependency>  
    <groupId>org.java-websocket</groupId>  
    <artifactId>Java-WebSocket</artifactId>  
    <version>1.6.0</version>  
</dependency>

基础构建

如何构建一个服务端

import org.java_websocket.WebSocket  
import org.java_websocket.handshake.ClientHandshake  
import org.java_websocket.server.WebSocketServer  
import java.lang.Exception  
import java.net.InetSocketAddress  
  
class VideoSocketServer(port: Int) : WebSocketServer(InetSocketAddress(port)) {  
  
    override fun onOpen(conn: WebSocket, handshake: ClientHandshake) {  
        // 获取连接头内容  
        println("新客户端连接:${conn.remoteSocketAddress}")  

    }  
  
    override fun onClose(conn: WebSocket, code: Int, reason: String, remote: Boolean) {  
		println("客户端断开:${closeCoon.remoteSocketAddress}")
    }  
  
    override fun onMessage(conn: WebSocket, message: String) {  
  
    }  
    override fun onError(conn: WebSocket?, ex: Exception) {  
        ex.printStackTrace()  
    }  
  
    override fun onStart() {  
        println("WebSocket 服务器已启动")  
    }  
}

如上就构建了一个WebSocket服务端,服务端的构建需要继承WebSocketServer抽象类,接下来分析上述API

名称 作用
open 当有客户端连接该服务端时触发
onClose 当有客户端从服务端断连时触发
onMessage 接受来自服务端的消息,onMessage有多种实现,可以接收文字消息,字节流消息,根据不同场景进行实现即可。消息发发送时,Java-WebSocket会自动选择适合的方法接收
onError 服务发生异常时触发
onStart 服务端启动时触发
通过ClientHandshake提供的getFieldValue()方法可以获取来自客服端请求的Header

如何启动这个服务端

fun main() {  
    val videoSocketServer = VideoSocketServer(8333)  
    videoSocketServer.start()  
}

如上,这个服务端就启动了,并且会自动产生阻塞,除非服务端停止

如何构建一个客户端

class VideoSendClient(uri: URI, header: HashMap<String, String>) : WebSocketClient(uri, header) {  
  
    override fun onOpen(handshake: ServerHandshake) {  
        println("客户端链接成功....")  
    }  
  
    override fun onMessage(message: String) {}  
  
    // 处理流  
    override fun onMessage(bytes: ByteBuffer) {  

    }  
  
    override fun onClose(code: Int, reason: String, remote: Boolean) {  
        println("客户端链接关闭")  
    }  
  
    override fun onError(e: Exception) {  
  
    }}

以上代码构建了一个客户端,需要继承WebSocketClient抽象类,WebSocketClient抽象类构造时还可以支持传入指定的header,也传入header

以下是一个客户端并添加header的示例

fun main() {  
	    // 初始化连接头,用以表示信息  
    private val header = HashMap<String, String>().also {  
        val readConfigProperty = ReadYamlUtils.readConfigProperty("send") as Map<*, *>  
        it["name"] =  readConfigProperty["name"].toString()  
        it["type"] = "send"  
        it["receive-client-name"] = readConfigProperty["receive-client-name"].toString()  
    }  

    socketServer = VideoSendClient(URI("ws://localhost:8333"), header)  
    socketServer.connect()  
    socketServer.send("this is a message")  
}

双向通信

使用Java-WebSocket简历一个A客户端发送消息B客户端接受的Demo
首先准备一个SocketClient对象,用于存放各个客户端的信息

import org.java_websocket.WebSocket  
  
class SocketClient(  
    // 客户端/服务端名称  
    var name: String,  
    // send/receive  
    var type: String,  
    // 接收端名称/发送端名称  
    var direction: String,  
    // socket链接服务  
    var socket: WebSocket  
)

接下来准备一个WebSocket服务端,用于转发发送方接收方

class VideoSocketServer(port: Int) : WebSocketServer(InetSocketAddress(port)) {  
  
    companion object {  
        // 准备两个集合,接收与发送方  
        val CONN_LIST = CopyOnWriteArrayList<SocketClient>()  
    }  
  
  
    override fun onOpen(conn: WebSocket, handshake: ClientHandshake) {  
        // 获取连接头内容  
        val name = handshake.getFieldValue("name")  
        val type = handshake.getFieldValue("type")  
        val direction = handshake.getFieldValue("direction")  
        CONN_LIST.add(SocketClient(name, type, direction, conn))  
        println("新客户端连接:${conn.remoteSocketAddress},name=$name,type=$type,direction=$direction")  
    }  
  
    override fun onClose(conn: WebSocket, code: Int, reason: String, remote: Boolean) {  
        println("客户端断开连接:${conn.remoteSocketAddress},code=$code,reason=$reason")  
        CONN_LIST.removeIf { it.socket == conn }  
    }  
  
    override fun onMessage(conn: WebSocket, message: String) {  
        // 判断消息是否来自发送方  
        val send = CONN_LIST.stream().filter { it.socket == conn && it.type == "send" }.findFirst().orElse(null)  
        println("接收到客户端消息:${conn.remoteSocketAddress},message=$message,from: name=${send.name},type=${send.type},direction=${send.direction}")  
        // 如果发送方已注册到集合中,获取其接收链接并向其发送消息  
        if (send != null) {  
            val receive =  
                CONN_LIST.stream().filter { it.direction == send.name && it.type == "receive" }.findFirst().orElse(null)  
            receive?.socket?.send(message)  
        }  
    }  
  
    override fun onError(conn: WebSocket?, ex: Exception) {  
        ex.printStackTrace()  
    }  
  
    override fun onStart() {  
        println("WebSocket 服务器已启动")  
    }  
  
}
// 服务端启动代码
fun main() {  
    val videoSocketServer = VideoSocketServer(8333)  
    videoSocketServer.start()  
}

上面的服务端代码中,所有的必要信息通过Header发送到服务端接收,并转换为对象存储在集合中
接下来准备发送端代码

class VideoSendClient(uri: URI, header: HashMap<String, String>) : WebSocketClient(uri, header) {  
  
    override fun onOpen(handshake: ServerHandshake) {  
        println("客户端链接成功,开始发送视频画面....")  
        this.send("this is a message")  
    }  
  
    override fun onMessage(message: String) {}  
  
    override fun onMessage(bytes: ByteBuffer) {  

    }  
  
    override fun onClose(code: Int, reason: String, remote: Boolean) {  
        println("客户端链接关闭")  
    }  
  
    override fun onError(e: Exception) {  
  
    }}
// 发送端启动代码
fun main() {  
	val header = HashMap<String, String>().also {  
	    val readConfigProperty = ReadYamlUtils.readConfigProperty("send") as Map<*, *>
	    it["name"] =  readConfigProperty["name"].toString()  
	    it["type"] = "send"  
	    it["direction"] = readConfigProperty["direction"].toString()  
	}
    val socketServer = VideoSendClient(URI("ws://localhost:8333"), header)
    socketServer.connect()
}

这里添加了一个测试消息,当消息建立时立即发送一条消息到服务端以验证服务是否成功
然后准备接受方服务

import javafx.scene.image.ImageView  
import org.java_websocket.client.WebSocketClient  
import org.java_websocket.handshake.ServerHandshake  
import java.net.URI  
import java.nio.ByteBuffer  
  
  
class VideoReceiveClient(uri: URI, header: HashMap<String, String>) :  
    WebSocketClient(uri, header) {  
  
    override fun onOpen(handshake: ServerHandshake) {  
        println("客户端链接成功,开始渲染视频画面....")  
    }  
  
    override fun onMessage(message: String) {  
        println("客户端接收到消息:$message")  
    }  
  
    // 处理流  
    override fun onMessage(bytes: ByteBuffer) {  

    }  
  
    override fun onClose(code: Int, reason: String, remote: Boolean) {  
        println("客户端链接关闭")  
    }  
  
    override fun onError(e: Exception) {  
  
    }}
// 接收端启动代码
fun main() {  
	val header = HashMap<String, String>().also {  
	    val readConfigProperty = ReadYamlUtils.readConfigProperty("receive") as Map<*, *>  
	    it["name"] =  readConfigProperty["name"].toString()  
	    it["type"] = "receive"  
	    it["direction"] = readConfigProperty["direction"].toString()  
	}
    val socketServer = VideoSendClient(URI("ws://localhost:8333"), header)
    socketServer.connect()
}

接收方收到消息,之后会立马打印

posted @ 2025-03-12 09:24  nan1mono  阅读(209)  评论(0)    收藏  举报