Свифт Network.framework WebSocket рукопожатие ноль вернулся

Я пытаюсь использовать новую Network.framework для подключения к WebSocket, но перед сервером нет ответа на рукопожатие.

(Да, я знаю, что Starscream существует, но он не поддерживает прокси / мобильность переключения пользователей между сетевым интерфейсом)

Мой тестовый код:

func beginTest() {

    let connection = NWConnection(host: "echo.websocket.org", port: 443, using: .tls)

    connection.stateUpdateHandler = { state in
        print("State:", state)
        switch state {
        case .ready:
            self.connectionReady(connection)
        default:
            break
        }
    }
    connection.start(queue: .main)
}

func connectionReady(_ connection: NWConnection) {

    let raw = """
    GET / HTTP/1.1
    Upgrade: websocket
    Connection: Upgrade
    Host: echo.websocket.org
    Origin: https://echo.websocket.org
    Sec-WebSocket-Key: s04nPqA7M6pQ3Lu2jRJLSQ==
    Sec-WebSocket-Version: 13
    """

    let rawData = raw.appending("\n\n\n").replacingOccurrences(of: "\n", with: "\r\n").data(using: .utf8)

    connection.send(content: rawData!, completion: .idempotent)

    connection.receiveMessage(completion: {data, context, bool, error in
        if let data = data {
            print("Received:", String(data: data, encoding: .utf8))
        }

        print("Error:", error)

        let hello = "Hello".data(using: .utf8)
        connection.send(content: hello, completion: .idempotent)
    })
}

Это нулевой ответ и соединение разорвано вместо того, чтобы получить ответ Обновление рукопожатия от сервера, ниже с журналами консоли:

State: preparing
State: ready
Received: nil
Error: nil
2018-10-08 11:38:57.314885+0800 SwiftNetworkTest[86448:3026660] [] nw_socket_handle_socket_event [C1.1:2] Socket SO_ERROR [54: Connection reset by peer]

Кто-нибудь может подсказать мне, как использовать Apple новую Network.framework? Это будет высоко ценится!

Update1

  • Мой плохой, теперь я могу видеть ответ рукопожатия с использованием .ascii кодировка вместо .utf8,

  • Но я все еще не могу подключиться Connection reset by peer, Как сохранить соединение после обновления до WebSocket?

1 ответ

Вы должны следовать рекомендациям Websocket, как форматировать отправленное Websocket сообщение.

Я думаю, что это хороший ресурс. Я использовал это сам.

https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers

После прочтения документации: https://developer.apple.com/documentation/security/certificate_key_and_trust_services/trust/evaluating_a_trust_and_parsing_the_result

Я настраиваю свое аутентифицированное TLS-соединение следующим образом:

    init(endpoint: NWEndpoint, interface: NWInterface?, passcode: String, delegate: BitfinexConnectionDelegate)
    {
        self.delegate            = delegate
        self.initiatedConnection = false

        let host = "api.bitfinex.com"
        let port = 443
        
        let options = NWProtocolTCP.Options()
        options.connectionTimeout = 15
        
        let tlsOptions = NWProtocolTLS.Options()
        sec_protocol_options_set_verify_block(
            tlsOptions.securityProtocolOptions,
            {
                (sec_protocol_metadata, sec_trust, sec_protocol_verify_complete) in
                
                let trust = sec_trust_copy_ref(sec_trust).takeRetainedValue()
                
                let pinner = FoundationSecurity()
                
                pinner.evaluateTrust(trust: trust, domain: host, completion:
                {
                    (state) in
                    
                    switch state
                    {
                    case .success:
                        sec_protocol_verify_complete(true)
                    case .failed(_):
                        sec_protocol_verify_complete(false)
                    }
                })
            }, queue
        )
        
        let parameters = NWParameters(tls: tlsOptions, tcp: options)
        let conn = NWConnection(host: NWEndpoint.Host.name(host, nil),
                                port: NWEndpoint.Port(rawValue: UInt16(port))!,
                                using: parameters
        )
        self.connection = conn
        
        startConnection()
    }

Блок FoundationSecurity() представляет собой простую оценку TLS.

if SecTrustEvaluateWithError(trust, &error)
{
    completion(.success)
}
else
{
    completion(.failed(error))
}

Как только мое соединение было готово. Я отправил через объект данных, который создал вот так. Это зависит от API, с которым вы взаимодействуете.

    private func prepareWebSocket() throws -> Data
    {
        let apiKey    = "API_KEY"
        let apiSecret = "API_SECRET"
        let authNonce = NonceProvider.sharedInstanse.nonce
        let authPayload = "AUTH\(authNonce)"
        
        
        let authenticationKey  = SymmetricKey(data: apiSecret.data(using: .ascii)!)
        let authenticationCode = HMAC<SHA384>.authenticationCode(for: authPayload.data(using: .ascii)!,
                                                                 using: authenticationKey
        )
        
        let authSig = authenticationCode.compactMap { String(format: "%02hhx", $0) }.joined()
        
        let payload: [String : Any] =
        [
            "event":       "auth",
            "apiKey" :     apiKey,
            "authSig":     authSig,
            "authPayload": authPayload,
            "authNonce":   authNonce
        ]

        return try JSONSerialization.data(withJSONObject: payload, options: .fragmentsAllowed)
    }
Другие вопросы по тегам