outputStreams stops writing sometimes.

I'm using NetService to connect to iostreams of one ios device to another and I'm using the streams to send/receive data between the two ios devices. But the data transfer sometimes stops suddenly without any error and after a few minutes it gives the error "Operation timed out. Socket is not connected". This happens rarely but it does happen and I've looked around but did not find any solution related to this.



Here is the code for write method.


extension OutputStream {
        func write(data: Data) -> Int {
  
            var bytesRemaining = data.count
            var totalBytesWritten = 0
            var bytesWritten = 0
  
            while bytesRemaining > 0 {
                    bytesWritten = data.withUnsafeBytes {
                    self.write(
                        $0.advanced(by: totalBytesWritten),
                        maxLength: bytesRemaining
                    )
                }
      
      
                if bytesWritten < 0 {
                    return -1
                } else if bytesWritten == 0 {
                    return totalBytesWritten
                }
      
                bytesRemaining -= bytesWritten
                totalBytesWritten += bytesWritten
           }
  
           return totalBytesWritten
      }//end method
    }//end extension



Here is the code for read method.


func readDataFrom2(_ aStreamP: Stream) {
        var buffer = [UInt8](repeating: 0, count: bufferSize)
  
        if aStreamP == self.connectedInputStream, let inputStream = self.connectedInputStream {
      
            while (inputStream.hasBytesAvailable){
                let len = inputStream.read(&buffer, maxLength: buffer.count)
                if(len > 0) {
                    let streamedData = Data.init(bytes: buffer, count: len)
                    self.readData += streamedData
                }//end if len > 0
          
            }//end whileLoop
        }//end if inputStream
  
    }//end method


self.readData is Data property of the class where I have this read method.

Replies

It looks like you’re using these streams synchronously. I recommend against that in general, although I’ve no reason to believe that it’s causing this specific problem.

[Assuming you’re doing this on a secondary thread. If you’re doing this on the main thread, all bets are off.]

With regards this problem, you should look at the traffic on the ‘wire’ to see what’s happening. Use an RVI packet trace on both sides of the connection to see where the data is getting ‘stuck’. See Recording a Packet Trace for info on how to set that up.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi eskimo,
Thanks for the reply. I'm using background thread to read/write and using the main thread to update UI(progress bar) so I guess it counts as async.
I'll look into packet tracing and get back if I find anything.

I'm using background thread to read/write and using the main thread to update UI(progress bar) so I guess it counts as async.

No, that’s using the sync API on a background thread. That’s less than ideal — for networking, it’s generally best to use async APIs — but it does avoid you getting killed by the watchdog.

I'll look into packet tracing and get back if I find anything.

Cool.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

async APIs ?
I'm fairly new to iOS Development, so I don't know of any other api's to acheive the work I'm doing.
Could you please point to one such API ?

If you’re just getting started then I’m going to recommend that you do this work using the Network framework, and specifically

NWConnection
. Its API for wrangling TCP connections is a lot more pleasant than the stream API, especially if you’re coming from Swift.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

But isn't NWConnection available on only iOS 12+ ? What about earlier iOS versions ?

But isn't

NWConnection
available on only iOS 12+?

Correct. Most developers I work with have a “current and current-1” policy, which means that, now that iOS 13 is shipping, it’s time to start thinking about dropping support for iOS 11.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi eskimo,


I haven't been able to figure out the problem and I can't use API other than streams because I'm trying to communicate between iOS and android devices without an intermediary server. Basically I wish to transfer files(images,videos,etc.) between iOS & android devices and after searching online I found that using NetService I could accomplish this. I use NetService to discover the other device and then connect to it's streams.

What I want to ask is that is if there is any async Api that I can use instead of streams in this scenario or is there any way to use streams api asynchronously ?

I can't use API other than streams because I'm trying to communicate between iOS and android devices without an intermediary server.

I think you’re missing a key point here. When you browse for connections using

NSNetServiceBrowser
, that’s using the Bonjour protocols on the wire [1]. When you open a stream pair using
NSNetService
, that’s using the Bonjour protocols to resolve the server and TCP to connect. Any API that supports the Bonjour protocols and TCP will be able to connect in this way, and that includes
NWConnection
.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] Specificlly:

But is there a way to use the streams api in async ?

But is there a way to use the streams api in async ?

Yeah. Sorry I didn’t spell that out earlier. You can run a stream pair asynchronously by scheduling it on the run loop. There are lots of example of this on the developer web site. Let’s start with [… picks one at random] the PictureSharing sample code.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

isn't there a more up-to-date and/or swift example for this ?
also does scheduling on a run loop work like this ?


myInputStream?.schedule(in: RunLoop.current, forMode: RunLoop.Mode.default)


is this correct ?

isn't there a more up-to-date and/or swift example for this ?

I don’t think we have any official samples that show how to use input and output streams from Swift. Honestly, if I had time to work on such things, I’d write them for

NWConnection
.

However, if you look around, you’ll find plenty of folks doing this. For example, a quick search of DevForums turned up this post that shows most of what you need.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I've somewhat dealt with the previous problem but now I've run into another. The netservice and streams connection is terminated when screen is locked.
I've looked but haven't found a suitable solution. How do I keep the connection alive even if the device is locked ?

I've somewhat dealt with the previous problem but now I've run into another.

Please start a new thread for this. It’s time to put this thread to bed IMO.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"