Swift NSStream sending multiple distincts commands

236 views Asked by At

I need to get the status of a list of devices from my home automation server. The devices I want to query for are in an array.

I'm triyng to loop thru that array, and for each devices, I'm doing a send to the server. The problem I have is that the server receive only one string containing my 3 commands.

The loop send this 3 commands:

gs,6297\r\n

gs,5867\r\n

gs,9737\r\n

I read in a lot of place that I only need to append a carriage return line feed to solve my problem but it’s not working.

I’ve used Wireshark to analyse what was happening. The 3 commands are sent as one big string:

gs,6297..gs,5867..gs,9737..

Where .. is 0d 0a.

I’ve implement my NSStream like seen in many place using the run-loop way:

outputStream!.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)

This is my Send function:

func send(message:String){
    if (self.outputStream!.hasSpaceAvailable){
        let data:NSData = message.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)!
        let bytesWritten = self.outputStream!.write(UnsafePointer(data.bytes), maxLength: data.length)

        println("> \(message) | Length: \(data.length)")
    } else {
        println("# stream busy")
    }
}

And my querying loop:

func GetDeviceStatus(array: [sDevice]){
    for (index, value) in enumerate(array) {
        while (true) {
            if (self.outputStream!.hasSpaceAvailable){
                self.send("gs,\(value.DevRef)\r\n")
                sleep(1)
                break
            }
        }
    }
}

Perhaps, the loop is to fast. If I uncomment the sleep(1), the server receive 3 commands and the Read() function receive 3 distincts responses. All is working. But adding that sleep function is blocking and slow…

Anybody can help? I’ve spent to much time with this issue.

1

There are 1 answers

3
rob mayoff On

Your problem is that you think TCP preserves message boundaries, but it doesn't. A TCP connection is a stream of bytes, not a stream of messages. Your server can't assume that it will read each command as a separate "message". Instead, it needs to look through the bytes it reads and break the bytes up on the \r\n boundaries.