Kitura

APIDoc Build Status - Master macOS Linux Apache 2 Slack Status

Kitura-WebSocket-NIO

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

API 概览

以下是 Kitura-WebSocket API 的概述,有关更多信息,请参阅 API 参考

使用 WebSocket 协议时,客户端连接到在特定服务器上运行的 WebSocket 服务。WebSocket 服务通过路径在特定服务器上标识。此路径在用于将连接从 HTTP 1.1 升级到 WebSocket 的升级请求中发送。

Kitura-WebSocket API 使用 WebSocketConnection 类反映该交互,该类表示 WebSocket 客户端到服务的连接,并使用 WebSocketService 协议,该协议由 WebSocket 服务的类实现。

特定的 WebSocketConnection 对象连接到特定的 WebSocketService 实例。另一方面,特定的 WebSocketService 实例连接到许多 WebSocketConnection 对象。

WebSocketConnection

WebSocketConnection 类提供:

WebSocketService

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 形式的消息。

WebSocket

实现 WebSocketService 协议的类按以下方式注册到服务器:

WebSocket.register(service: WebSocketService, onPath: String)

此函数传递正在注册的 WebSocketService 以及正在注册的路径。

可以从服务器取消注册已注册的 WebSocketService,如下所示:

WebSocket.unregister(path: String)

此函数传递已取消注册的 WebSocketService 正在注册的路径。

Autobahn 测试套件

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 由 connecteddisconnected 函数维护,它们分别从字典中添加和删除连接。

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 文档

有关更多信息,请访问我们的 API 参考

社区

我们喜欢讨论服务器端 Swift 和 Kitura。 加入我们的 Slack 与团队见面!

许可

该库是在 Apache 2.0 许可下获得许可的。完整的许可证文本可在 LICENSE 中获得。