How to test if my remote socket NSStream are correctly open

11,703

First of all, you have to schedule the stream on a runloop:

inputStream!.scheduleInRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
outputStream!.scheduleInRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)

And, in your code, it's too soon to check the error. Because open() is async operation, you have to wait the result using delegate. Here is working example:

import Foundation

class Connection: NSObject, NSStreamDelegate {
var host:String?
var port:Int?
var inputStream: NSInputStream?
var outputStream: NSOutputStream?

func connect(host: String, port: Int) {

    self.host = host
    self.port = port

    NSStream.getStreamsToHostWithName(host, port: port, inputStream: &inputStream, outputStream: &outputStream)

    if inputStream != nil && outputStream != nil {

        // Set delegate
        inputStream!.delegate = self
        outputStream!.delegate = self

        // Schedule
        inputStream!.scheduleInRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
        outputStream!.scheduleInRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)

        print("Start open()")

        // Open!
        inputStream!.open()
        outputStream!.open()
    }
}

func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
    if aStream === inputStream {
        switch eventCode {
        case NSStreamEvent.ErrorOccurred:
            print("input: ErrorOccurred: \(aStream.streamError?.description)")
        case NSStreamEvent.OpenCompleted:
            print("input: OpenCompleted")
        case NSStreamEvent.HasBytesAvailable:
            print("input: HasBytesAvailable")

            // Here you can `read()` from `inputStream`

        default:
            break
        }
    }
    else if aStream === outputStream {
        switch eventCode {
        case NSStreamEvent.ErrorOccurred:
            print("output: ErrorOccurred: \(aStream.streamError?.description)")
        case NSStreamEvent.OpenCompleted:
            print("output: OpenCompleted")
        case NSStreamEvent.HasSpaceAvailable:
            print("output: HasSpaceAvailable")

            // Here you can write() to `outputStream`

        default:
            break
        }
    }
}

}

Then:

let conn = Connection()
conn.connect("www.example.com", port: 80)
Share:
11,703
Admin
Author by

Admin

Updated on June 13, 2022

Comments

  • Admin
    Admin almost 2 years

    TL;DR : What's the way to check if my remote stream are opened correctly after a call to NSStream.getStreamsToHostWithName(...)?

    My application is a mobile IOS8 swift application.

    I am using NSStream for input and output socket communication with a remote server.

    To connect to my server and open my stream I use this code:

    func connect(host: String, port: Int) -> Bool
    {
        //clear the previous connection if existing (and update self.connected)
        disconnect()
        //updating the current connection
        self.host = host
        self.port = port
    
        //pairing NSstreams with remote connection
        NSStream.getStreamsToHostWithName(self.host!, port: self.port!, inputStream: &inputStream, outputStream: &outputStream)
    
        if (self.inputStream != nil && self.outputStream != nil)
        {
            //open streams
            self.inputStream?.open()
            self.outputStream?.open()
        }
        if self.outputStream?.streamError == nil && self.inputStream?.streamError == nil
        {
            println("SOK")    //PROBLEM 1
        }
        //error checking after opening streams // PROBLEM 2
        if var inputStreamErr: CFError = CFReadStreamCopyError(self.inputStream)?
        {
            println("InputStream error : " + CFErrorCopyDescription(inputStreamErr))
        }
        else if var outputStreamErr: CFError = CFWriteStreamCopyError(self.outputStream)?
        {
            println("OutStream error : " + CFErrorCopyDescription(outputStreamErr))
        }
        else
        {
            //set the delegate to self
            self.inputStream?.delegate = self
            self.outputStream?.delegate = self
            self.connected = true
        }
        //return connection state
        return self.connected
    }
    

    My problem is located at //PROBLEM1 and //PROBLEM2.

    At these points I try to determine if my sockets are opened correctly, but even if the server is not running this code still works, then the read and write operations are failing. I would like to be able to determine if the connection failed or not.

    Maybe I am doing it totally wrong, I don't get how to test this.

  • Admin
    Admin about 9 years
    Thanks for this precise answer. I just have some questions. First, does doing the schedule part make my streams async? I want my operations to be synchronous.
  • rintaro
    rintaro about 9 years
    With my understanding, stream itself is always non-blocking. If you need synchronous operation, you have to use polling with while true { ... } loop. see: developer.apple.com/library/ios/documentation/Cocoa/Conceptu‌​al/…
  • Admin
    Admin about 9 years
    I think stream is blocking, the NSInputStream.read() operation is blocking by default
  • Admin
    Admin about 9 years
    Anyway, I used your answer to reshape my whole class. I am starting swift and it made me grasp delegates, events handling and runloop in swift. Thanks a lot!
  • Miracle Johnson
    Miracle Johnson about 9 years
    Where i have to write this two lines ? inputStream!.scheduleInRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode) outputStream!.scheduleInRunLoop(.mainRunLoop(), forMode: NSDefaultRunLoopMode)
  • tp2376
    tp2376 over 5 years
    I am having same problem here : stackoverflow.com/questions/51938300/… . I added handle Event method after this but it's not triggering Any help Please..