mre*_*dig 5 websocket ios swift urlsession
我已经URLSessionWebSocketDelegate设置并实施了
urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?)
Run Code Online (Sandbox Code Playgroud)
然而,如果服务器正确断开连接,它似乎只会影响委托。如果连接断开或服务器不提供断开连接代码,则委托函数永远不会运行。我还尝试检查URLSessionWebSocketTask属性closeCode以及closeReason断开连接之前和之后,除非服务器发送正确的断开连接代码,否则它们不会更改。
虽然我可以控制服务器并且可以确定故意断开连接有代码,但如果网络连接中断会发生什么?或者如果服务器宕机了?我认为委托函数仍然应该被调用。
有趣的是,我的监听函数出现错误,错误内容如下:
Error Domain=NSPOSIXErrorDomain Code=57 "Socket is not connected" UserInfo={NSErrorFailingURLStringKey=[urlomitted], NSErrorFailingURLKey=[urlomitted]
Run Code Online (Sandbox Code Playgroud)
因此,虽然如果我看到错误 57,我可以手动断开套接字,但我不知道这是否适用于所有不同的断开连接变体。
我认为我要么做错了什么,要么这是一个错误,但我找不到其他人有同样的问题,所以我想我应该在提交雷达之前询问。
完全按照我在示例中所做的操作,它可以正常工作,没有任何问题。它管理连接状态,当您需要再次重新连接时,它使用 connect 方法重新初始化套接字。
@available(iOS 13.0, *)
class NativeWebSocket: NSObject, WebSocketProvider, URLSessionDelegate, URLSessionWebSocketDelegate {
var delegate: WebSocketProviderDelegate?
private var socket: URLSessionWebSocketTask!
private var timeout: TimeInterval!
private var url: URL!
private(set) var isConnected: Bool = false
init(url: URL, timeout: TimeInterval) {
self.timeout = timeout
self.url = url
super.init()
}
// do not move create socket to init method because if you want to reconnect it never connect again
public func connect() {
let configuration = URLSessionConfiguration.default
let urlSession = URLSession(configuration: configuration, delegate: self, delegateQueue: OperationQueue())
let urlRequest = URLRequest(url: url, timeoutInterval: timeout)
socket = urlSession.webSocketTask(with: urlRequest)
socket.resume()
readMessage()
}
func send(data: Data) {
socket.send(.data(data)) { error in
self.handleError(error)
}
}
func send(text: String) {
socket.send(.string(text)) { error in
self.handleError(error)
}
}
private func readMessage() {
socket.receive { result in
switch result {
case .failure:
break
case .success(let message):
switch message {
case .data(let data):
self.delegate?.webSocketDidReciveData(self, didReceive: data)
case .string(let string):
self.delegate?.webSocketDidReciveData(self, didReceive: string.data(using: .utf8)!)
@unknown default:
print("un implemented case found in NativeWebSocketProvider")
}
self.readMessage()
}
}
}
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
isConnected = true
delegate?.webSocketDidConnect(self)
}
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
isConnected = false
}
/// never call delegate?.webSocketDidDisconnect in this method it leads to close next connection
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
completionHandler(.useCredential, URLCredential(trust: challenge.protectionSpace.serverTrust!))
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
if let error = error {
handleError(error)
}
}
func closeConnection() {
socket.cancel(with: .goingAway, reason: nil)
}
/// we need to check if error code is one of the 57 , 60 , 54 timeout no network and internet offline to notify delegate we disconnected from internet
private func handleError(_ error: Error?) {
if let error = error as NSError? {
if error.code == 57 || error.code == 60 || error.code == 54 {
isConnected = false
closeConnection()
delegate?.webSocketDidDisconnect(self, error)
} else {
delegate?.webSocketReceiveError(error)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
小智 1
不确定这是一个好方法,但是下面的两个解决方案确实捕获了我的代码中服务器/连接事件的丢失。
a) 您可以在 WebSocket 接收函数中检测到它,如下所示:
func receiveMessage() {
webSocketTask?.receive { result in
defer { self.receiveMessage() }
switch result {
case .failure(let error):
print("Error in receiving message: \(error)")
let code = (error as NSError).code
if code == 60 || code == 57 || code == 54 {
// deal with error
}
case .success(let message):
switch message {
case let .string(string):
// deal with strings message
case let .data(data):
// deal with data message
@unknown default:
// deal with unknown message
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
b) 或者您可以添加一个 urlSession 实例方法来URLSessionWebSocketDelegate捕获服务器/连接错误的一般丢失。
extension BlipSocket: URLSessionWebSocketDelegate {
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didOpenWithProtocol protocol: String?) {
DispatchQueue.main.async {
self.isConnected = true
}
}
func urlSession(_ session: URLSession, webSocketTask: URLSessionWebSocketTask, didCloseWith closeCode: URLSessionWebSocketTask.CloseCode, reason: Data?) {
DispatchQueue.main.async {
self.isConnected = false
}
}
func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError: Error?) {
DispatchQueue.main.async {
self.connectionError = true
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6140 次 |
| 最近记录: |