10

I'm sending a file between two devices using iOS 7's Multipeer Connectivity Framework. I'm using NSStreams to tranfer the file, as my previous attempt using MCSession's sendData:toPeers:withMode was really unreliable. Unfortunately the transfer speeds I'm getting are really slow, around 100kb/s, which won't work for the application I'm working on. Here are my Input and Output stream delegate methods, which is where the file transfer happens.

Output Stream (in the delegate for the stream)

...//previous code
 case NSStreamEventHasSpaceAvailable: {
            //we will only open the stream when we want to send the file.

            NSLog(@"Stream has space available");
            //[self updateStatus:@"Sending"];

            // If we don't have any data buffered, go read the next chunk of data.

            if (totalBytesWritten< outgoingDataBuffer.length) {
                //more stuff to read
                int towrite;
                int diff = outgoingDataBuffer.length-packetSize;
                if (diff <= totalBytesWritten)
                {
                    towrite = outgoingDataBuffer.length - totalBytesWritten;
                } else
                    towrite = packetSize;
                NSRange byteRange = {totalBytesWritten, towrite};
                uint8_t buffer[towrite];
                [outgoingDataBuffer getBytes:buffer range:byteRange];


                NSInteger bytesWritten = [outputStream write:buffer maxLength:towrite];
                totalBytesWritten += bytesWritten;
                NSLog(@"Written %d out of %d bytes",totalBytesWritten, outgoingDataBuffer.length);
            } else {
                //we've written all we can write about the topic?
                NSLog(@"Written %d out of %d bytes",totalBytesWritten, outgoingDataBuffer.length);
                [self endStream];
            }

            // If we're not out of data completely, send the next chunk.
        } break;

Input Stream

- (void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode {

    switch(eventCode) {
        case NSStreamEventHasBytesAvailable:
        {
            NSLog(@"Bytes Available");
            //Sent when the input stream has bytes to read, we need to read bytes or else this wont be called again
            //when this happens... we want to read as many bytes as we can

            uint8_t buffer[1024];
            int bytesRead;

            bytesRead = [inputStream read:buffer maxLength:sizeof(buffer)];
            [incomingDataBuffer appendBytes:&buffer length:bytesRead];
            totalBytesRead += bytesRead;
            NSLog(@"Read %d bytes, total read bytes: %d",bytesRead, totalBytesRead);

        }break;
        case NSStreamEventEndEncountered:
        {
            UIImage *newImage = [[UIImage alloc]initWithData:incomingDataBuffer];
            [[self.detailViewController imageView] setImage:newImage];
            NSLog(@"End Encountered");

            [self closeStream];
            //this should get called when there aren't any more bytes being sent down the stream
        }
    }
 }

Is there a way to speed up this file transfer through either multithreading or using a slightly modified NSStream subclass that makes use of asynchronous sockets?

Marco
  • 6,692
  • 2
  • 27
  • 38
Corey Zambonie
  • 614
  • 5
  • 17
  • Are you still browsing for peers? This article ( http://mzsanford.com/blog/ios7-multipeer-wifi-slow/index.html ) talks about how browsing/advertising can affect your overall wifi performance. Also, do you have this working going from device to simulator? I can go from Sim to Device, but when I try to send to the Sim my input stream attempts to read data once and it finds zero data then it disconnects. – Brian Oct 11 '13 at 16:36
  • Hey Brian. My setup consists of two ipad mini's running separate applications executing a file transfer. I'm still browsing for peers after the browser and advertiser connect because when I stop browsing for peers I lose the connection to the device. I was running into similar issues with the frequent disconnection while using the sendData:toPeers method. That is why I switched to using the Stream methods. – Corey Zambonie Oct 11 '13 at 17:36
  • Its just strange because Air Drop from device to device works so fast, but executing a file transfer is really slow. Apple must be doing some behind the scenes magic for its own implementation. – Corey Zambonie Oct 11 '13 at 17:41
  • Have you had any luck with this yet? I am also experiencing lower than expected bandwidth with this new API. I am using WIFI ad-hoc mode. AirDrop and WIFI tethering are both way faster than what I am seeing in my app... – bradleyrzeller Oct 23 '13 at 10:12
  • 1
    Seeing the same problems as well. Really amazingly slow transfer speeds. Seems like a bug in multi peer framework. – jjxtra Oct 25 '13 at 04:54

3 Answers3

3

There are a couple of things I have noticed that cause slow file transfers:

I have been getting decent speeds (and by decent I mean 500K / second) between an iPhone 5S, iPad Air and iPhone Simulator on the MAC.

jjxtra
  • 20,415
  • 16
  • 100
  • 140
1

I had some pretty decent transfer rates going for a while and suddenly it seemed that I was receiving one packet every 15 to 30 seconds. All looked fine on the sender side, but the packets trickle into the receiver. I use sendData:toPeers:withMode in my app.

One of my devices had WiFi turned off. Turning it back on restored my performance even though neither device is connected to a wifi network.

So I'm only ever doing peer-to-peer ad-hoc connections with MPC, but still, with no WiFi hub involved, it appears that iOS is making use of the WiFi signal to carry my data.) I did see in a presentation from Apple a while back that MPC over straight BlueTooth is a dog and I can tell you for a fact that it is.

Dan Loughney
  • 4,647
  • 3
  • 25
  • 40
1

MPC work on WiFi or bluetooth so it depends on what you are using. If you are using wifi to send files than you will get maximum speed as per the network strength.

Kevin Mac
  • 320
  • 2
  • 10