Swift Network.framework WebSocket 握手 nil 返回
Posted
技术标签:
【中文标题】Swift Network.framework WebSocket 握手 nil 返回【英文标题】:Swift Network.framework WebSocket handshake nil returned 【发布时间】:2018-10-08 03:49:37 【问题描述】:我正在尝试使用新的 Network.framework 连接到 WebSocket,但面临来自服务器的零握手响应。
(是的,我知道红蜘蛛存在,但它不支持代理/移动用户在网络接口之间切换)
我的测试代码:
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?将不胜感激!
更新1
对不起,我现在可以看到使用.ascii
编码而不是.utf8
的握手响应。
但我的连接仍然断开Connection reset by peer
。升级到 WebSocket 后如何保持连接?
【问题讨论】:
【参考方案1】:您应该遵循 Websocket 指南如何格式化 Websocket 发送的消息。
我认为这是一个很好的资源。我自己用过。
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_servers
【讨论】:
【参考方案2】:阅读文档后: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)
【讨论】:
以上是关于Swift Network.framework WebSocket 握手 nil 返回的主要内容,如果未能解决你的问题,请参考以下文章
如何为 Network.framework 编写 NWProtocolFramer,使用分隔符将流拆分为帧?
Case1-basic network framework/Related organization‘s name