hey, I need to have a tcp socket (client) for a mobile device. Is there a standard way to do this in swift? If there isn't, is there a standard way in objectif c?
Thanks in advance!
hey, I need to have a tcp socket (client) for a mobile device. Is there a standard way to do this in swift? If there isn't, is there a standard way in objectif c?
Thanks in advance!
You can call BSD Sockets from Swift but it’s not a lot of fun. If you want to go down this path, see the Socket API Helper section of the UnsafeRawPointer Migration doc.
I generally recommend that you
Stream
, part of Foundation, for this sort of thing. Your starting point here should be
getStreamsToHost(withName:port:inputStream:outputStream:)
.
You can also use the newer URLSessionStreamTask.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
Hi,
Thanks for the reply,
What I need is an event triggered receive function, do you have any examples of an event handler when the client receives message?
Thanks in advance
What I need is an event triggered receive function …?
All the APIs I mentioned are capable of doing that (even BSD Sockets, with a little help from GCD).
On the NSStream front, there’s tonnes of examples of this, including:
None of them are in Swift, but the concepts map across directly from Objective-C. To get you started I’ve pasted some Swift code in below, which is taken from a test project that I use for exploring issues like this.
Share and Enjoy
—
Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware
let myEmail = "eskimo" + "1" + "@apple.com"
import UIKit
extension Stream {
static func streamsToHost(name hostname: String, port: Int) -> (inputStream: InputStream, outputStream: OutputStream) {
var inStream: InputStream? = nil
var outStream: OutputStream? = nil
Stream.getStreamsToHost(withName: hostname, port: port, inputStream: &inStream, outputStream: &outStream)
return (inStream!, outStream!)
}
}
class StreamViewer : UITableViewController, StreamDelegate {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
switch (indexPath.section, indexPath.row) {
case (0, 0):
self.streamTest()
case (0, 1):
self.pingTest()
default:
fatalError()
}
self.tableView.deselectRow(at: indexPath, animated: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
if let streams = self.streams {
self.stop(streams: streams)
}
}
var streams: (inputStream: InputStream, outputStream: OutputStream)? = nil
var ping = Data()
func streamTest() {
if let streams = self.streams {
NSLog("stream stop")
self.stop(streams: streams)
} else {
NSLog("stream start")
self.start(name: "imap.mail.me.com", port: 993, tls: true, ping: "a001 NOOP\r\n")
// self.start(name: "localhost", port: 12345, tls: false, ping: "Hello Cruel World!\r\n")
}
}
func pingTest() {
if let streams = self.streams {
NSLog("stream ping")
self.ping(streams: streams)
} else {
NSLog("stream ping while not connected")
}
}
func start(name: String, port: Int, tls: Bool, ping: String) {
self.ping = ping.data(using: .utf8)!
let streams = Stream.streamsToHost(name: name, port: port)
self.streams = streams
if tls {
let success = streams.inputStream.setProperty(StreamSocketSecurityLevel.negotiatedSSL as AnyObject, forKey: Stream.PropertyKey.socketSecurityLevelKey)
precondition(success)
}
for s in [streams.inputStream, streams.outputStream] {
s.schedule(in: .current, forMode: .defaultRunLoopMode)
s.delegate = self
s.open()
}
}
func ping(streams: (inputStream: InputStream, outputStream: OutputStream)) {
let data = self.ping
let dataCount = data.count
let bytesWritten = data.withUnsafeBytes { (p: UnsafePointer<UInt8>) -> Int in
return streams.outputStream.write(p, maxLength: dataCount)
}
if bytesWritten < 0 {
NSLog("stream write error")
} else if bytesWritten < data.count {
NSLog("stream write short %d / %d", bytesWritten, data.count)
} else {
NSLog("stream task write %@", data as NSData)
}
}
func stop(streams: (inputStream: InputStream, outputStream: OutputStream)) {
for s in [streams.inputStream, streams.outputStream] {
s.delegate = nil
s.close()
}
self.streams = nil
}
func stream(_ thisStream: Stream, handle eventCode: Stream.Event) {
guard let streams = self.streams else { fatalError() }
let streamName = thisStream == streams.inputStream ? " input" : "output"
switch eventCode {
case [.openCompleted]:
NSLog("%@ stream did open", streamName as NSString)
break
case [.hasBytesAvailable]:
NSLog("%@ stream has bytes", streamName as NSString)
var buffer = [UInt8](repeating: 0, count: 2048)
let bytesRead = streams.inputStream.read(&buffer, maxLength: buffer.count)
if bytesRead > 0 {
NSLog("%@ stream read %@", streamName, NSData(bytes: &buffer, length: bytesRead))
}
case [.hasSpaceAvailable]:
NSLog("%@ stream has space", streamName as NSString)
case [.endEncountered]:
NSLog("%@ stream end", streamName)
self.stop(streams: streams)
case [.errorOccurred]:
let error = thisStream.streamError! as NSError
NSLog("%@ stream error %@ / %d", streamName, error.domain, error.code)
self.stop(streams: streams)
default:
fatalError()
}
}
}
Now that getStreamsToHost is deprecated. What is the recommended call to open TCP Socket streams?
https://developer.apple.com/documentation/foundation/stream/1414311-getstreamstohost