Websocket connection issue in iOS? - ios

I am using web socket connection in my app. When I am trying to establish the web socket connection and it's not connected. I am using the Starscream for making the web socket connection. I've tried with many test WS Url for testing and none of the url is working. Currently I am testing in simulator. Are there any proxy issues or firewall issue?.
class ViewController: UIViewController, WebSocketDelegate {
var socket: WebSocket!
override func viewDidLoad() {
super.viewDidLoad()
let urlString = "wss://echo.websocket.org" // testing url
var request = URLRequest(url: URL(string: urlString)!)
request.timeoutInterval = 30
socket = WebSocket(request: request)
socket.delegate = self
socket.pongDelegate = self as? WebSocketPongDelegate
socket.connect()
}
// MARK: Websocket Delegate Methods.
// Never call this method
func websocketDidConnect(socket: WebSocketClient) {
print("websocket is connected")
}
func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
if let e = error as? WSError {
print("websocket is disconnected: \(e.message)")
} else if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
print("Received text: \(text)")
}
func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
print("Received data: \(data.count)")
}
}

Couple of things to check in case you haven't done these:
Remember apple blocks all non https urls by default. Change arbitrary loads to YES in -
info.plist -> App Transport Security Settings > Allow Arbitrary Loads
Set self.socket.selfSignedSSL = true

Related

Not able to connect Web Socket

I'm using "Swifter" as my local HTTP Server.
I'm using "Starscream" for WebSockets.
Unfortunately getting websocket is disconnected: Optional("The operation couldn’t be completed. (Starscream.WSError error 1.)")) when i'm trying to connect.
I tries accessing localhost from browser and it looks like Http Server is working fine.
Below is the code that I'm working on:
SimpleServer:
import Foundation
import Swifter
class SimpleServer{
let server: HttpServer = HttpServer()
public func startServer(){
do {
server["/hello"] = { .ok(.htmlBody("You asked for bhuvesh \($0)")) }
try server.start(8000)
}
catch{
print("Server could not be started")
}
}
}
ViewController:
import UIKit
import Starscream
class ViewController: UIViewController, WebSocketDelegate {
#IBOutlet weak var button: UIButton!
var socket: WebSocketClient!
var simpleServer = SimpleServer()
override func viewDidLoad() {
super.viewDidLoad()
simpleServer.startServer()
socket = WebSocket(url: URL(string: "ws://localhost:8000")!)
socket.delegate = self
socket.connect()
}
func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
print("websocket is disconnected: \(error?.localizedDescription))")
}
func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
print("got some text: \(text)")
}
func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
print("got some data: \(data.count)")
}
func websocketDidConnect(socket: WebSocketClient) {
print("websocket is connected")
}
}
Im having the exact same problem. Have you tried connecting to it with your Mac and websocat?
If it fails there two then its probably something about your server if not you probably have the exact same problem as me.

Socket won't connect with Starscream

I am using Starscream to open up a websocket. The problem is that it does't connect on localhost or with the server.
var socket = WebSocket(url: NSURL(string: "ws://localhost:8080/")!)
self.socket.voipEnabled = true;
socket.delegate = self
socket.connect()
func websocketDidConnect(ws: WebSocket) {
print("websocket is connected")
}
func websocketDidDisconnect(ws: WebSocket, error: NSError?) {
print("websocket is disconnected: \(error?.localizedDescription)")
}
func websocketDidReceiveMessage(ws: WebSocket, text: String) {
print("Received text: \(text)")
}
func websocketDidReceiveData(ws: WebSocket, data: NSData) {
print("Received data: \(data.length)")
}
func websocketDidReceivePong(socket: WebSocket) {
print("Got pong!")
}
#IBAction func writeText(sender: UIBarButtonItem) {
socket.writeString("hello there!")
}
it started connected once I added self.socket.selfSignedSSL = true;

Starscream's socket.isConnected is always returning false

I'm developing an iOS application using Swift that connects to an Android device via sockets. I've implemented Starscream and was able to connect to the other device. My issue is that when I print something on the websocketDidConnect delegate method, it does not print. Also when I print socket.isConnected, it prints false. Kindly help me. Thanks. Other alternatives to Starscream are also welcome, thanks!
Here is my code:
import Starscream
class SettingsViewController: UIViewController, UITextFieldDelegate, WebSocketDelegate{
override func viewDidLoad() {
super.viewDidLoad()
let socket = WebSocket(url: NSURL(string: "ws://\(ipAddressTextField.text!):4000/")!)
socket.connect()
print("socket.isConnected \(socket.isConnected)") //this one is false
socket.onConnect = {
print("Connected...") // does not print
}
socket.onDisconnect = { (error: NSError?) in
print("websocket is disconnected: \(error?.localizedDescription)") // this one prints when I turn the wifi off
}
socket.onData = { (data: NSData) in
print("got some data: \(data.length)")
}
}
func websocketDidConnect(ws: WebSocket) {
print("websocket is connected")
}
func websocketDidDisconnect(ws: WebSocket, error: NSError?) {
if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
func websocketDidReceiveMessage(ws: WebSocket, text: String) {
print("Received text: \(text)")
}
func websocketDidReceiveData(ws: WebSocket, data: NSData) {
print("Received data: \(data.length)")
}
}
You need to make it as a class property otherwise it will be released as it gets out of viewDidLoad method.

How to successfully handle sftp:// protocol by subclassing NSURLProtocol?

The built-in URL protocols supported by NSURLConnection can handle the schemes http, https, file, ftp, about, and data. I want to support sftp. I heard that there is a way to achieve this by subclassing NSURLProtocol. But I'm not getting how to do it. I want to download a image from the folder through sftp.
Source: https://www.raywenderlich.com/76735/using-nsurlprotocol-swift
The tutorial says by subclassing we can support custom URL. But when i ran the code the connection always fails. I thought when we try connecting to sftp , delegate method in MyURLProtocol.swift i.e didReceiveAuthenticationChallenge would get called but that doesn't happen. Instead delegate method didFailWithError gets called. I not getting why the connection is failing. Both these methods are from NSURLConnectionDelegate
I have a ViewController.swift
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let urlString = "sftp://username#192.168.0.1:22/batman"
// Open a connection for the URL.
var url = NSURL(string: urlString)
request = NSURLRequest(URL: url!)
connection = NSURLConnection(request: request, delegate: self, startImmediately: true)//(request: request, delegate: self)
}
In My AppDelegate.swift
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
NSURLProtocol.registerClass(MyURLProtocol)
return true
}
My MyURLProtocol.swift
import UIKit
import CoreData
var requestCount = 0
class MyURLProtocol: NSURLProtocol, NSURLConnectionDelegate {
var connection: NSURLConnection!
var mutableData: NSMutableData!
var response: NSURLResponse!
override class func canInitWithRequest(request: NSURLRequest) -> Bool {
print("Request #\(requestCount++): URL = \(request.URL!.absoluteString)")
if NSURLProtocol.propertyForKey("MyURLProtocolHandledKey", inRequest: request) != nil {
return false
}
return true
}
override class func canonicalRequestForRequest(request: NSURLRequest) -> NSURLRequest {
return request
}
override class func requestIsCacheEquivalent(aRequest: NSURLRequest,
toRequest bRequest: NSURLRequest) -> Bool {
return super.requestIsCacheEquivalent(aRequest, toRequest:bRequest)
}
override func startLoading() {
// 1
let possibleCachedResponse = self.cachedResponseForCurrentRequest()
if let cachedResponse = possibleCachedResponse {
print("Serving response from cache")
// 2
let data = cachedResponse.valueForKey("data") as! NSData
let mimeType = cachedResponse.valueForKey("mimeType") as! String
let encoding = cachedResponse.valueForKey("encoding") as! String
// 3
let response = NSURLResponse(URL: self.request.URL!, MIMEType: mimeType, expectedContentLength: data.length, textEncodingName: encoding)
// 4
self.client!.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .NotAllowed)
self.client!.URLProtocol(self, didLoadData: data)
self.client!.URLProtocolDidFinishLoading(self)
} else {
// 5
print("Serving response from NSURLConnection")
let newRequest = self.request.mutableCopy() as! NSMutableURLRequest
NSURLProtocol.setProperty(true, forKey: "MyURLProtocolHandledKey", inRequest: newRequest)
self.connection = NSURLConnection(request: newRequest, delegate: self)
}
}
override func stopLoading() {
if self.connection != nil {
self.connection.cancel()
}
self.connection = nil
}
func connection(connection: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
self.client!.URLProtocol(self, didReceiveResponse: response, cacheStoragePolicy: .NotAllowed)
self.response = response
self.mutableData = NSMutableData()
}
func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
self.client!.URLProtocol(self, didLoadData: data)
self.mutableData.appendData(data)
}
func connectionDidFinishLoading(connection: NSURLConnection!) {
self.client!.URLProtocolDidFinishLoading(self)
self.saveCachedResponse()
}
func connection(connection: NSURLConnection, didFailWithError error: NSError) {
self.client!.URLProtocol(self, didFailWithError: error)
}
func connection(connection: NSURLConnection, didReceiveAuthenticationChallenge challenge: NSURLAuthenticationChallenge) {
}
func saveCachedResponse () {
print("Saving cached response")
// 1
let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context = delegate.managedObjectContext
// 2
let cachedResponse = NSEntityDescription.insertNewObjectForEntityForName("CachedURLResponse", inManagedObjectContext: context) as NSManagedObject
cachedResponse.setValue(self.mutableData, forKey: "data")
cachedResponse.setValue(self.request.URL!.absoluteString, forKey: "url")
cachedResponse.setValue(NSDate(), forKey: "timestamp")
cachedResponse.setValue(self.response.MIMEType, forKey: "mimeType")
cachedResponse.setValue(self.response.textEncodingName, forKey: "encoding")
// 3
do {
try context.save()
} catch let error as NSError {
print(error)
print("Could not cache the response")
}
}
func cachedResponseForCurrentRequest() -> NSManagedObject? {
// 1
let delegate = UIApplication.sharedApplication().delegate as! AppDelegate
let context = delegate.managedObjectContext
// 2
let fetchRequest = NSFetchRequest()
let entity = NSEntityDescription.entityForName("CachedURLResponse", inManagedObjectContext: context)
fetchRequest.entity = entity
// 3
let predicate = NSPredicate(format:"url == %#", self.request.URL!.absoluteString)
fetchRequest.predicate = predicate
// 4
let possibleResult:Array<NSManagedObject>?
do {
possibleResult = try context.executeFetchRequest(fetchRequest) as? Array<NSManagedObject>
if let result = possibleResult {
if !result.isEmpty {
return result[0]
}
}
} catch let error as NSError {
print(error)
}
return nil
}
}
Adding support for the URL scheme itself doesn't add support for the underlying network protocol. The sftp protocol is unrelated to HTTP, and requires entirely different networking code to make the connection and download data. Right now, your custom protocol class is basically just asking the URL loading system to make a new sftp request whenever your protocol gets an sftp URL (or any other URL). This will always fail because the URL loading system doesn't know how to handle sftp requests.
To add sftp support, you would need to bring in an actual sftp library, and then use that instead of creating a new NSURLConnection in your startLoading method. You also need to check the protocol in canInitWithRequest to make sure it really is an sftp request, IIRC. Otherwise, your custom protocol subclass will end up handling all requests for all possible URL schemes.
With that said, unless there's a really good reason to handle sftp using NSURLConnection or NSURLSession, you're probably better off just handling that by using one of those sftp libraries directly, rather than trying to plumb them into the URL loading system.
For info on sftp libraries, see this question:
SFTP libraries for iPhone?

How to Call Web Service in Web Socket in iOS?

currently i am making chat application using Web Socket.
My question is How to Call Web Service in Web Socket ?
In iOS using swift you can use two Cocoapods Library which makes your work hassle free and
1) Starscream
2) RocketSocket
With reference to Starscream follow are very handy example:
import UIKit
import Starscream
class ViewController: UIViewController, WebSocketDelegate {
var socket: WebSocket!
override func viewDidLoad() {
super.viewDidLoad()
var request = URLRequest(url: URL(string: "http://localhost:8080")!)
request.timeoutInterval = 5
socket = WebSocket(request: request)
socket.delegate = self
socket.connect()
}
// MARK: Websocket Delegate Methods.
func websocketDidConnect(socket: WebSocketClient) {
print("websocket is connected")
}
func websocketDidDisconnect(socket: WebSocketClient, error: Error?) {
if let e = error as? WSError {
print("websocket is disconnected: \(e.message)")
} else if let e = error {
print("websocket is disconnected: \(e.localizedDescription)")
} else {
print("websocket disconnected")
}
}
func websocketDidReceiveMessage(socket: WebSocketClient, text: String) {
print("Received text: \(text)")
}
func websocketDidReceiveData(socket: WebSocketClient, data: Data) {
print("Received data: \(data.count)")
}
// MARK: Write Text Action
#IBAction func writeText(_ sender: UIBarButtonItem) {
socket.write(string: "hello there!")
}
// MARK: Disconnect Action
#IBAction func disconnect(_ sender: UIBarButtonItem) {
if socket.isConnected {
sender.title = "Connect"
socket.disconnect()
} else {
sender.title = "Disconnect"
socket.connect()
}
}
}

Resources