上下文
我正在开发一个Mac应用程序。在这个应用程序中,我想运行一个websocket服务器。为此,我使用了Swift和Websocket。我的完整设置在下面。
问题
Websocket和SwiftNIO的所有文档都面向创建一个服务器端进程,该进程在您从命令行启动它时启动,然后无限地运行。
在我的应用程序中,我必须能够启动websocket服务器,然后根据需要关闭它并重新启动它,而无需重新启动我的应用程序。下面的代码可以做到这一点,但我想确认两件事:
test()函数中,我向所有连接的客户端发送一些文本。我不确定这是否是线程安全和正确。我可以像在这里一样存储WebSocket实例并从我的应用程序的主线程发送消息吗?serverBootstrap(group:)[...].bind(host:port:).wait()的结果会创建一个Channel,然后无限等待。当我在关联的shutdownGracefully()上调用EventLoopGroup时,该服务器是否被正确清理?(在关闭之后,我可以确认端口5759又是免费的,所以我猜一切都清理了吗?)感谢您的输入;很难在应用程序中找到使用SwiftNIO和Websocket的例子。
代码
import Foundation
import NIO
import NIOHTTP1
import NIOWebSocket
import WebSocketKit
@objc class WebsocketServer: NSObject
{
private var queue: DispatchQueue?
private var eventLoopGroup: MultiThreadedEventLoopGroup?
private var websocketClients: [WebSocket] = []
@objc func startServer()
{
queue = DispatchQueue.init(label: "socketServer")
queue?.async
{
let upgradePipelineHandler: (Channel, HTTPRequestHead) -> EventLoopFuture<Void> = { channel, req in
WebSocket.server(on: channel) { ws in
ws.send("You have connected to WebSocket")
DispatchQueue.main.async {
self.websocketClients.append(ws)
print("websocketClients after connection: \(self.websocketClients)")
}
ws.onText { ws, string in
print("received")
ws.send(string.trimmingCharacters(in: .whitespacesAndNewlines).reversed())
}
ws.onBinary { ws, buffer in
print(buffer)
}
ws.onClose.whenSuccess { value in
print("onClose")
DispatchQueue.main.async
{
self.websocketClients.removeAll { (socketToTest) -> Bool in
return socketToTest === ws
}
print("websocketClients after close: \(self.websocketClients)")
}
}
}
}
self.eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 2)
let port: Int = 5759
let promise = self.eventLoopGroup!.next().makePromise(of: String.self)
let server = try? ServerBootstrap(group: self.eventLoopGroup!)
// Specify backlog and enable SO_REUSEADDR for the server itself
.serverChannelOption(ChannelOptions.backlog, value: 256)
.serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
.childChannelInitializer { channel in
let webSocket = NIOWebSocketServerUpgrader(
shouldUpgrade: { channel, req in
return channel.eventLoop.makeSucceededFuture([:])
},
upgradePipelineHandler: upgradePipelineHandler
)
return channel.pipeline.configureHTTPServerPipeline(
withServerUpgrade: (
upgraders: [webSocket],
completionHandler: { ctx in
// complete
})
)
}.bind(host: "0.0.0.0", port: port).wait()
_ = try! promise.futureResult.wait()
}
}
///
/// Send a message to connected clients, then shut down the server.
///
@objc func test()
{
self.websocketClients.forEach { (ws) in
ws.eventLoop.execute {
ws.send("This is a message being sent to all websockets.")
}
}
stopServer()
}
@objc func stopServer()
{
self.websocketClients.forEach { (ws) in
try? ws.eventLoop.submit { () -> Void in
print("closing websocket: \(ws)")
_ = ws.close()
}.wait() // Block until complete so we don't shut down the eventLoop before all clients get closed.
}
eventLoopGroup?.shutdownGracefully(queue: .main, { (error: Error?) in
print("Eventloop shutdown now complete.")
self.eventLoopGroup = nil
self.queue = nil
})
}
}发布于 2020-11-16 10:24:46
在test()函数中,我向所有连接的客户端发送一些文本。我不确定这是否是线程安全和正确。我可以像在这里一样存储WebSocket实例并从我的应用程序的主线程发送消息吗?
就像你在这里做的一样,是的,那应该是安全的。ws.eventLoop.execute将在属于该WebSocket连接的事件循环线程上执行该块。这会很安全的。
当我在关联的EventLoopGroup上调用shutdownGracefully()时,服务器是否被正确清理?(我可以确认,在这次关闭之后,端口5759又是免费的,所以我猜所有的东西都清理干净了?)
是。shutdownGracefully强制关闭所有连接和侦听套接字。
https://stackoverflow.com/questions/64852971
复制相似问题