4

我正在尝试在我的 iOS 应用程序中创建 websocket 服务器和客户端,我在此处的示例实现的帮助下成功地做到了这一点。(https://github.com/apple/swift-nio/tree/master/Sources/NIOWebSocketServer) - 所以目前的工作情况是,我在应用程序启动时运行 websocket 服务器,然后我在可以连接的 web 视图中加载客户端给它。

现在我的问题是我希望我的服务器保护 websocket 服务器(基本上从 HTTPS html 页面连接到 websocket 服务器)

我是网络编程的新手,至少可以说缺少 Swift-nio 文档。据我了解,我可以使用(https://github.com/apple/swift-nio-transport-services

我发现这个线程正是我需要的 - https://github.com/apple/swift-nio-transport-services/issues/39 - 我可以禁用 TLS 身份验证,因为我不在乎我的用例,只要我可以连接websocket。

所以我的问题是如何扩展我的客户端(https://github.com/apple/swift-nio/tree/master/Sources/NIOWebSocketClient)和服务器(https://github.com/apple/swift-nio/ tree/master/Sources/NIOWebSocketServer ) 使用 swift-nio-transport-service。

我可以添加NIOSSLContextand 东西,但我认为我需要添加EventLoopGroupand 新bootstrap方法。我知道答案就在那里......但我似乎无法确定它。

任何指针将不胜感激。

谢谢。

4

2 回答 2

6

要将一个简单的NIO服务器转换为NIOTransportServices一个,您需要进行以下更改:

  1. 将依赖项添加NIOTransportServices到您的服务器。
  2. 更改MultiThreadedEventLoopGroupNIOTSEventLoopGroup
  3. 更改ClientBootstrapNIOTSConnectionBootstrap
  4. 更改ServerBootstrapNIOTSListenerBootstrap
  5. 构建并运行您的代码。

有些ChannelOptions 在 中不起作用NIOTransportServices,但大多数都可以:确认事情是否正常运行的最简单方法是快速测试通用流程。

这不会为您的应用程序添加任何额外的功能,但它确实为您提供了使用 iOS API 的相同功能。

要将 TLS 添加到NIOTSConnectionBootstrapNIOTSListenerBootstrap,请使用该.tlsOptions函数。例如:

NIOTSListenerBootstrap(group: group)
    .tlsOptions(myTLSOptions())

配置 aNWProtocolTLS.Options是一件有点棘手的事情。您需要获得一个SecIdentity,这需要与钥匙串进行交互。奎因在这里讨论了一些。

一旦你有了SecIdentity,你可以像这样使用它:

func myTLSOptions() -> NWProtocolTLS.Options {
    let options = NWProtocolTLS.Options()
    let yourSecIdentity = // you have to implement something here
    sec_protocol_options_set_local_identity(options.securityProtocolOptions, sec_identity_create(yourSecIdentity)
    return options
}

编写完代码后,一切都会顺利进行!


作为扩展,如果你想保护 Linux 上的 NIO 服务器,你可以使用swift-nio-ssl来实现。这有单独的配置,因为钥匙串 API 不可用,因此您需要从文件中加载更多的密钥和证书。

于 2019-08-12T18:52:55.657 回答
0

我需要一个不使用SecIdentityor的安全 websocket NIOTransportServices,所以根据@Lukasa 的提示,swift-nio-ssl我拼凑了一个看起来可以正常工作的示例。

我不知道它是否正确,但我把它放在这里以防其他人可以受益。try为简洁起见,省略了失败时的错误处理和中止。

let configuration = TLSConfiguration.forServer(certificateChain: try! NIOSSLCertificate.fromPEMFile("/path/to/your/tlsCert.pem").map { .certificate($0) }, privateKey: .file("/path/to/your/tlsKey.pem"))
let sslContext = try! NIOSSLContext(configuration: configuration)
            
let upgradePipelineHandler: (Channel, HTTPRequestHead) -> EventLoopFuture<Void> = { channel, req in
                
    WebSocket.server(on: channel) { ws in

       ws.send("You have connected to WebSocket")

       ws.onText { ws, string in
           print("Received text: \(string)")
       }
                
       ws.onBinary { ws, buffer in
           // We don't accept any Binary data
       }
                
       ws.onClose.whenSuccess { value in
           print("onClose")
       }
   }
}

self.eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 2)
let port: Int = 5759
let promise = self.eventLoopGroup!.next().makePromise(of: String.self)
            
_ = 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 handler = NIOSSLServerHandler(context: sslContext)
        _ = channel.pipeline.addHandler(handler)
              
        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()
try! server.close(mode: .all).wait()
于 2020-11-17T00:55:48.480 回答