I'm trying to connect to wss socket, and the host name looks like this: "myhostname.com/ws/v2". Here is how I start the connection:
let host = "myhostname.com/ws/v2"
CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host as CFString, 443, &readStream, &writeStream)
inputStream = readStream!.takeRetainedValue()
outputStream = writeStream!.takeRetainedValue()
outputStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL, forKey: Stream.PropertyKey.socketSecurityLevelKey)
inputStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL, forKey: Stream.PropertyKey.socketSecurityLevelKey)
inputStream.schedule(in: .current, forMode: .commonModes)
outputStream.schedule(in: .current, forMode: .commonModes)
inputStream.delegate = self
outputStream.delegate = self
inputStream.open()
outputStream.open()
This fails with an error:
The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 1.)
However, if I remove the path from the host name, so it looks like this: myhostname.com
then in my delegate I get an event openCompleted
. However, it doesn't respond to my messages after that, I assume it's because I'm connected to a wrong socket, since I removed the path.
What is the proper way of connecting to a socket when the host name has an additional path?
myhostname.com/ws/v2
is not a hostname. It is an (incomplete) URL (the complete URL is wss://myhostname.com/ws/v2
). The hostname is just myhostname.com
, and the Websocket path on that host is just /ws/v2
.
The WebSockets handshake uses HTTP/S, so it is not enough to just connect to the host with an NSStream
. You have to connect a TCP socket to the host
and port, then negotiate an SSL/TLS handshake if using WSS, then use HTTP to request the path
asking for an Upgrade
to WebSocket, and only if a successful HTTP 101
reply is returned then perform the WebSocket handshake.
That is a lot of work to do manually. You really should be using an actual WebSocket client library instead. There are plenty available.