I have an iOS and a Mac app that establish a peer-to-peer connection through Bonjour/NSNetService. (based on the WiTap sample code)
In some cases, both devices won’t receive data anymore after a few seconds while they are still able to write data out (i.e. without an error being reported).
The data written to the NSOutputStream never makes it to the NSInputStream of the other side.
The strange part is that sending and receiving works right after the connection is established. It seems to go bad after a few seconds.I know, because I have each side send a “Ping” message between each other (literally the string “Ping\r\n”) every 4 seconds.
The first Ping makes it across each time, but in about 50% of the cases, all subsequent Ping commands get lost without an error being reported.
If it works, I get output like this:
iPhone: 1 [OK] Sent Ping to Mac
Mac: 2 [OK] Got Ping from iPhone
Mac: 3 [OK] Sent Ping to iPhone
iPhone: 4 [OK] Got Ping from Mac
iPhone: 5 [OK] Sent Ping to Mac
Mac: 6 [OK] Got Ping from iPhone
Mac: 7 [OK] Sent Ping to iPhone
iPhone: 8 [OK] Got Ping from Mac
... and so on ...
If it does not work:
iPhone: 1 [OK] Sent Ping to Mac
Mac: 2 [OK] Got Ping from iPhone
Mac: 3 [OK] Sent Ping to iPhone
iPhone: 4 [OK] Got Ping from Mac
iPhone: 5 [OK] Sent Ping to Mac
Mac: 6 [OK] Sent Ping to iPhone
iPhone: 7 [!!] OVERDUE Ping from Mac
Mac: 8 [!!] OVERDUE Ping from iPhone
iPhone: 9 [OK] Connection closed by user ← I close the connection through the UI
Mac: 0 [OK] Sent Ping to iPhone ← Mac still sending happily ever after
Mac: 1 [OK] Sent Ping to iPhone
Mac: 2 [OK] Sent Ping to iPhone
Both devices are on the local WiFi network, Bluetooth is OFF on both devices.The iPhone publishes the NSNetService (includesPeerToPeer = true), the Mac discovers the service and connects to it.
Did anybody run into a similar issue? Is there any way I can track this down? I get a handle of the underlying socket every 4 seconds to check if it is valid, and it reports “true” each time.
Service code:
let server = NSNetService(domain: "local.", type: serviceType, name: serviceName, port: 0)
server.includesPeerToPeer = true
server.delegate = self
server.publishWithOptions(.ListenForConnections)
Reading:
case NSStreamEvent.HasBytesAvailable where aStream == inputStream:
var readBuffer = [UInt8](count: 3, repeatedValue: 0)
let bytesRead = inputStream.read(&readBuffer, maxLength: readBuffer.count)
if bytesRead > 0
{
inputBuffer.appendBytes(readBuffer, length: bytesRead)
_processBufferAndNotifyDelegate(inputBuffer)
}
else
{
_closeStreamsAndNotifyDelegate()
}
Writing:
case NSStreamEvent.HasSpaceAvailable where aStream == outputStream && outputBuffer.length > 0:
outputStreamHasSpaceAvailable = true
_startWritingOutputBuffer()
private func _startWritingOutputBuffer()
{
if outputBuffer.length == 0 { return }
let actuallyWritten = outputStream.write(UnsafePointer(outputBuffer.bytes), maxLength: outputBuffer.length)
if actuallyWritten > 0
{
outputStreamHasSpaceAvailable = false
// Remove from the buffer whatever we wrote. Remaining bytes, should there be any,
// will be written on next HasSpaceAvailable event
outputBuffer.replaceBytesInRange(NSMakeRange(0, actuallyWritten), withBytes: nil, length: 0)
}
else
{
// Error or end of file
_closeStreamsAndNotifyDelegate()
}
}
EDIT:
I ran some more tests and I'm starting to think that this could be an issue with having a Mac and an iOS device connected via Bluetooth. I added a basic Mac client to the WiTap sample code and can now reproduce this every time. At first, taps from iOS are received on the Mac, but if I stop tapping on the iPhone, the connection goes stale after a few seconds and the Mac won't receive any data. Both still think the connection is up and running, by the way. WiFi and Bluetooth are enabled on both devices.