Kitura-WebSocket-NIO 是基于 swift-nio 实现的 Kitura-WebSocket API。它为基于 Kitura 的服务器提供了使用 WebSocket 协议(RFC 6455)接收和发送消息到客户端的能力。它与各种 WebSocket 客户端兼容,包括:
Kitura-WebSocket-NIO 支持 WebSocket 协议的第十三版。
Kitura-WebSocket 同时支持 WS 和 WSS (SSL/TLS 安全 WS) 协议。要启用 WSS,请为基于 Kitura 的服务器设置 SSL/TLS 支持。有关详细信息,请参阅 在 Kitura 服务器上启用 SSL/TLS 教程,网址为 www.kitura.io。
Kitura-WebSocket-NIO 还支持使用 permessage-deflate 算法进行 WebSocket 压缩,尽可能遵守 RFC 7692。
将 Kitura-WebSocket-NIO
包添加到应用程序 Package.swift
文件中的依赖项。将 "x.x.x"
替换为最新的 Kitura-WebSocket-NIO
发布版本。
.package(url: "https://github.com/Kitura/Kitura-WebSocket-NIO.git", from: "x.x.x")
将 Kitura-WebSocket
添加到你的目标依赖项中
.target(name: "example", dependencies: ["Kitura-WebSocket"]),
import KituraWebSocket
以下是 Kitura-WebSocket API 的概述,有关更多信息,请参阅 API 参考。
使用 WebSocket 协议时,客户端连接到在特定服务器上运行的 WebSocket 服务。WebSocket 服务通过路径在特定服务器上标识。此路径在用于将连接从 HTTP 1.1 升级到 WebSocket 的升级请求中发送。
Kitura-WebSocket API 使用 WebSocketConnection
类反映该交互,该类表示 WebSocket 客户端到服务的连接,并使用 WebSocketService
协议,该协议由 WebSocket 服务的类实现。
特定的 WebSocketConnection
对象连接到特定的 WebSocketService
实例。另一方面,特定的 WebSocketService
实例连接到许多 WebSocketConnection
对象。
WebSocketConnection 类提供:
向客户端发送文本和二进制消息的函数。
WebSocketConnection.send(message: Data)
WebSocketConnection.send(message: String)
优雅和强制关闭连接的函数。
WebSocketConnection.close(reason: WebSocketCloseReasonCode?=nil, description: String?=nil)
WebSocketConnection.drop(reason: WebSocketCloseReasonCode?=nil, description: String?=nil)
在 close()
和 drop()
中,WebSocketCloseReasonCode
枚举提供标准 WebSocket 关闭原因代码,并能够指定特定于应用程序的代码。
一个唯一的标识符,可用于帮助管理连接到 WebSocketService
的 WebSocketConnection
对象集合。
id: String
WebSocketService 协议使 Kitura-WebSocket 能够通知 WebSocket 服务关于发生的一系列事件。这些事件包括:
connected(connection: WebSocketConnection)
disconnected(connection: WebSocketConnection, reason: WebSocketCloseReasonCode)
reason 参数包含与客户端断开连接关联的原因代码。它可能来自客户端发送的关闭命令,或者如果连接的套接字突然关闭,则由 Kitura-WebSocket 确定。
received(message: Data, from: WebSocketConnection)
message 参数包含 Data 结构形式的消息字节。
received(message: String, from: WebSocketConnection)
message 参数包含 String 形式的消息。
实现 WebSocketService
协议的类按以下方式注册到服务器:
WebSocket.register(service: WebSocketService, onPath: String)
此函数传递正在注册的 WebSocketService
以及正在注册的路径。
可以从服务器取消注册已注册的 WebSocketService
,如下所示:
WebSocket.unregister(path: String)
此函数传递已取消注册的 WebSocketService
正在注册的路径。
Kitura-WebSocket-NIO 完全符合 WebSockets 的 Autobahn 测试套件。 要创建一个回显服务器并针对其运行此测试套件,请按照 此处的说明进行操作。
此示例是一个简单的聊天服务,用于演示如何使用 Kitura-WebSocket API。 服务器端是用 Swift 使用 Kitura-WebSocket 编写的,客户端是用 JavaScript 使用 Node.js 和 websocket NPM 包编写的。 以下说明向您展示如何创建服务器和客户端的文件,以及如何编译和运行应用程序。
为了运行客户端,必须安装 Node.js。
服务器跟踪已连接到它的客户端,并将发送给它的所有文本消息回显到已连接到它的所有客户端,发送消息的客户端除外。
您需要创建服务器的目录结构,如下所示:
ServerDirectory ├── Package.swift └── Sources └── ChatServer ├── ChatService.swift └── main.swift
创建一个包含以下内容的 Package.swift
文件,将 "x.x.x"
替换为 Kitura、HeliumLogger 和 Kitura-WebSocket-NIO 的最新版本
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "ChatServer",
dependencies: [
.package(url: "https://github.com/Kitura/Kitura.git", .upToNextMinor(from: "x.x.x")),
.package(url: "https://github.com/Kitura/HeliumLogger.git", from: "x.x.x"),
.package(url: "https://github.com/Kitura/Kitura-WebSocket-NIO.git", from: "x.x.x")
],
targets: [
.target(
name: "ChatServer",
dependencies: ["Kitura", "HeliumLogger", "Kitura-WebSocket"]),
]
)
虽然 HeliumLogger 包不是严格必需的,但添加它是为了启用日志记录。
创建一个包含以下内容的 ChatService.swift
文件
// ChatServer is a very simple chat server
import Foundation
import KituraWebSocket
class ChatService: WebSocketService {
private var connections = [String: WebSocketConnection]()
public func connected(connection: WebSocketConnection) {
connections[connection.id] = connection
}
public func disconnected(connection: WebSocketConnection, reason: WebSocketCloseReasonCode) {
connections.removeValue(forKey: connection.id)
}
public func received(message: Data, from: WebSocketConnection) {
from.close(reason: .invalidDataType, description: "Chat-Server only accepts text messages")
connections.removeValue(forKey: from.id)
}
public func received(message: String, from: WebSocketConnection) {
for (connectionId, connection) in connections {
if connectionId != from.id {
connection.send(message: message)
}
}
}
}
该类有一个 Dictionary,connections,用于跟踪所有已连接客户端的连接。 Dictionary 由 connected
和 disconnected
函数维护,它们分别从字典中添加和删除连接。
received
函数,它接收二进制消息,正在拒绝消息,关闭客户端连接并从已知连接集中删除连接。
最后,received
函数,它接收文本消息,只是将收到的消息回显到除了发送消息的客户端之外的所有客户端。
应该注意的是,所有这些函数都可以从多个线程同时调用。 在实际应用程序中,应该在访问应用程序的非线程安全工件(例如这个非常简单的示例中的 connections Dictionary)周围添加锁定。
创建一个包含以下内容的 main.swift
文件
// ChatServer is a very simple chat server
import Foundation
import KituraNet
import KituraWebSocket
import HeliumLogger
import LoggerAPI
// Using an implementation for a Logger
HeliumLogger.use(.info)
WebSocket.register(service: ChatService(), onPath: "chat")
class ChatServerDelegate: ServerDelegate {
public func handle(request: ServerRequest, response: ServerResponse) {}
}
// Add HTTP Server to listen on port 8080
let server = HTTP.createServer()
server.delegate = ChatServerDelegate()
do {
try server.listen(on: 8080)
ListenerGroup.waitForListeners()
} catch {
Log.error("Error listening on port 8080: \(error).")
}
在 main.swift 文件中
使用此服务器设置后,客户端应连接到聊天服务,网址为 ws://**host**:8080/chat,其中 **host** 是运行服务器的主机。
客户端有一个简单的命令行界面。在启动时,传递主机和端口号。客户端只是从终端读取要发送的消息,并在终端上显示收到的消息。
您需要创建客户端的目录结构,如下所示:
ClientDirectory ├── package.json └── chat.js
创建一个 package.json
文件,其中至少包含:
{
"name": "chat",
"description": "Simple chat server client",
"version": "0.0.1",
"engines": {
"node": ">=0.8.0"
},
"dependencies": {
"websocket": "^1.0.23"
}
}
创建一个包含以下内容的 chat.js
文件
/* main file of Simple Chat Server Client */
var readline = require('readline');
var WebSocketClient = require('websocket').client
var host = process.argv[2];
rl = readline.createInterface(process.stdin, process.stdout);
rl.setPrompt('> ');
rl.prompt();
var client = new WebSocketClient();
client.on('connectFailed', function(error) {
console.log('Connect Error: ' + error.toString());
process.exit();
});
client.on('connect', function(connection) {
connection.on('error', function(error) {
console.log("Connection Error: " + error.toString());
process.exit();
});
connection.on('close', function(reasonCode, description) {
console.log('chat Connection Closed. Code=' + reasonCode + ' (' + description +')');
});
connection.on('message', function(message) {
if (message.type === 'utf8') {
console.log('\r=> ' + message.utf8Data);
rl.prompt();
}
});
rl.on('line', function(line) {
connection.sendUTF(line);
rl.prompt();
});
rl.on('close', function() {
connection.close();
console.log('Have a great day!');
process.exit(0);
});
rl.prompt();
});
client.connect("ws://" + host +"/chat", "chat");
要构建服务器,请在服务器目录中键入
swift build
要运行服务器,请在同一目录中键入
.build/debug/ChatServer
服务器现在将启动并运行。 将显示以下信息性日志消息
[INFO] [HTTPServer.swift:124 listen(on:)] 正在监听端口 8080
要在客户端中设置客户端,只需
npm install
这将安装 websocket 包。
要运行客户端,再次在客户端目录中,运行
node chat.js host:8080
其中 **host** 是运行服务器的主机的主机名,例如,如果您的服务器在 localhost 上运行,则运行
node chat.js localhost:8080
如上所述,服务器将发送给它的所有文本消息回显到已连接到它的所有客户端,发送消息的客户端除外。因此,为了看到示例在运行,您需要将多个客户端连接到服务器。客户端可以在同一台计算机上的多个终端窗口中运行。然后,您可以在一个客户端上输入消息,并在另一个客户端上看到它出现,反之亦然。
有关更完整的示例,请参阅 Kitura-Sample。
有关更多信息,请访问我们的 API 参考。
我们喜欢讨论服务器端 Swift 和 Kitura。 加入我们的 Slack 与团队见面!
该库是在 Apache 2.0 许可下获得许可的。完整的许可证文本可在 LICENSE 中获得。