Receiving Data from NSInputStream in Swift
Asked Answered
P

2

18

I try to send and receive data with NSOutputStream and NSInputStream in Swift. The sending of data is working well, but i have some questions about the receiving.

I found a solution with handling the NSStreamEvent, which i have tried.

First of all my function for initializing the connection:

func initNetworkCommunication(){  
    var host : CFString = "127.0.0.1"
    var port : UInt32 = 7001
    var readstream : Unmanaged<CFReadStream>?
    var writestream : Unmanaged<CFWriteStream>?
    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, host, port, &readstream, &writestream)

    inputstream = readstream!.takeRetainedValue()
    outputstream = writestream!.takeRetainedValue()

    inputstream.delegate = self
    outputstream.delegate = self


    inputstream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
    outputstream.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

    inputstream.open()
    outputstream.open()   
}

This part is working. I have set the delegates to self, so i should be able to handle the NSStreamEvents in this class.

func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
    switch (eventCode){
    case NSStreamEvent.OpenCompleted:
        NSLog("Stream opened")
        break
    case NSStreamEvent.HasBytesAvailable:
        NSLog("HasBytesAvailable")
        break
    case NSStreamEvent.ErrorOccurred:
         NSLog("ErrorOccurred")
        break
    case NSStreamEvent.EndEncountered:
        NSLog("EndEncountered")
        break
    default:
        NSLog("unknown.")
    }
}

In my understanding everytime when some data arrives, it should print "HasBytesAvaible", but it printed "unknown." everytime. So i played around a bit and it worked with this:

func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {

    var buffer = [UInt8](count: 4096, repeatedValue: 0)
    while (inputstream.hasBytesAvailable){
        let result: Int = inputstream.read(&buffer, maxLength: buffer.count)
    }

    switch (eventCode){
    case NSStreamEvent.OpenCompleted:
        NSLog("Stream opened")
        break
    case NSStreamEvent.HasBytesAvailable:
        NSLog("HasBytesAvailable")
        var output = NSString(bytes: &buffer, length: buffer.count, encoding: NSUTF8StringEncoding)
        NSLog("output: %@", output)
        receiveMessage(output) //only adds the message to an array
        break
    case NSStreamEvent.ErrorOccurred:
        NSLog("ErrorOccurred")
        break
    case NSStreamEvent.EndEncountered:
          NSLog("EndEncountered")
        break
    default:
        NSLog("unknown.")
    }
}

It's working this way, but i wanted to ask you whether this is the right way ? What is the best practice at this point ?

UPDATE I worked on it again a few weeks ago and figured out my mistakes. So here is the working code.

func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) {
        switch (eventCode){
    case NSStreamEvent.ErrorOccurred:
        NSLog("ErrorOccurred")
        break
    case NSStreamEvent.EndEncountered:
        NSLog("EndEncountered")
        break
    case NSStreamEvent.None:
        NSLog("None")
        break
    case NSStreamEvent.HasBytesAvailable:
        NSLog("HasBytesAvaible")
        var buffer = [UInt8](count: 4096, repeatedValue: 0)
        if ( aStream == inputstream){

            while (inputstream.hasBytesAvailable){
                var len = inputstream.read(&buffer, maxLength: buffer.count) 
                if(len > 0){
                    var output = NSString(bytes: &buffer, length: buffer.count, encoding: NSUTF8StringEncoding) 
                    if (output != ""){
                        NSLog("server said: %@", output!)
                    }
                }
            } 
        }
        break
    case NSStreamEvent.allZeros:
        NSLog("allZeros")
        break
    case NSStreamEvent.OpenCompleted:
        NSLog("OpenCompleted")
        break
    case NSStreamEvent.HasSpaceAvailable:
        NSLog("HasSpaceAvailable")
        break
  }
Principate answered 14/10, 2014 at 12:36 Comment(3)
Hi, this solution working for multiple response at a time ?Giddens
The above code is for receiving a message, not for responding to it. There are frameworks for sending and responding with sockets, maybe take a look at socket.io socket.io/blog/socket-io-on-iosPrincipate
Yeah, its for receiving message but i want ask you is it going to handle if i got multiple responses from server at same time ?Giddens
D
3

You're missing the event hasSpaceAvailable, which I expect is occurring when it says "unknown". It's telling you that it is ready to receive more data.

Generally, I avoid using default in switch statements for enums, since the compiler will tell you when you've missed something.

Denten answered 29/1, 2015 at 12:23 Comment(4)
I figured it out a few weeks ago. I will accept your answer here, because you're right. This was my mistake.Principate
Glad you sorted it – I only realised the date of your question after I'd answered!Denten
@Alexander this solution will work for multiple response at a time ? in (UPDATE)Giddens
@K.Shrikant I think you'll get better answers if you create a new questionDenten
N
3

I am using the code written by hoedding, and noticed a mistake. The line:

var output = NSString(bytes: &buffer, length: buffer.count, encoding: NSUTF8StringEncoding)

should be replaced by:

var output = NSString(bytes: &buffer, length: len, encoding: NSUTF8StringEncoding)

You have to get in the output var only the number of characters returned by the server, and not the full length of the buffer, or you will get garbage from previous requests.

Nut answered 8/12, 2015 at 6:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.