Is there a standard tcp socket in swift for ios?

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!

Replies

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