0

I have a .NET desktop program running as a server and I'm trying to implement a port of my client program in iOS, but I'm getting some odd behavior from NSSocket. Here's the relevant code from the server.

public NetworkListener()
{
    _Stream = new MemoryStream();
    _tcpServer = new TcpListener(System.Net.IPAddress.Any, 8086);
    _endPoints = new List<EndPoint>();
}

public void BeginListening()
{
    _tcpServer.Start();
    _workerThread = new Thread(new ThreadStart(WorkerLoop));
    _workerThread.IsBackground = true;
    _workerThread.Start();
}

private void WorkerLoop()
{
    while(true)
    {
        _clientSocket = _tcpServer.AcceptSocket();
        _networkStream = new NetworkStream(_clientSocket, true);
        /* ... rest of method here ... */
    }
}

I'm attempting the following code in the iOSSimulator using XCode 4.2 and targeting iOS 5. The Mac that's hosting the simulator is on the same network as the server program and I can run a Java client that uses the same hardcoded local IP as below to connect just fine. In the Objective C code, I'm receiving some data and storing it in an NSData member property, then once the Socket is opened, I use the stream callback to tell me when to try sending data.

- (IBAction)connectToServer  
{
    NSURL *serverUrl = [NSURL URLWithString:@"10.0.0.5"];

    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)[serverUrl host], 8086, &readStream, &writeStream);

    [self setInStream:(NSInputStream *)readStream];
    [self setOutStream:(NSOutputStream *)writeStream];
    [self.inStream setDelegate:self];
    [self.outStream setDelegate:self];
    [self.inStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [self.outStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [self.inStream open];
    [self.outStream open];

    NSError *error = [self.outStream streamError];
    if (error) {
        NSLog(@"outstream error: %@", [error localizedDescription]);
    }
}

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    NSError *error;
    if ([aStream isEqual:outStream]) {
        switch (eventCode) {
            case NSStreamEventHasSpaceAvailable:
                NSLog(@"Stream has space!");
                [self writeDataToStream];
                break;
            case NSStreamEventOpenCompleted:
                NSLog(@"Stream is open!");
                break;
            case NSStreamEventErrorOccurred:
                error = [self.outStream streamError];
                NSLog(@"Stream error occured: %@", [error localizedDescription]);
                break;
            default:
                break;
        }
    }
}

- (void)writeDataToStream
{
    unsigned int byteIndex = 0;
    unsigned int length = data.length;
    uint8_t *buffer = (uint8_t *)[data bytes];

    while (byteIndex <= length) {    
        unsigned int bufferLength = (length - byteIndex >= 1024) ? 1024 : (length - byteIndex);
        uint8_t tempBuffer[bufferLength];

        (void)memcpy(tempBuffer, buffer, bufferLength);
        if (self.outStream.hasSpaceAvailable) {
            bufferLength = [self.outStream write:tempBuffer maxLength:bufferLength];
            byteIndex += bufferLength;
        } else
            NSLog(@"Stream is blocked!");
    }
}

In the XCode console, I see "Stream is open!", followed by "Stream has space!", followed by an exception that says "The operation couldn't be completed. Bad file descriptor". I placed a breakpoint in my server code right after _tcpServer.AcceptSocket(), but it never hits. It seems that the stream opens, but the socket never connects?

Duck Jones
  • 380
  • 1
  • 5
  • 16
  • You didn't indicate, but did you step through to see if you actually wrote anything to the socket? If you didn't, then your bufferLength variable becomes a -1. This will then continuously loop (because byteIndex never becomes larger than length! At some point your (length - byteIndex) will go less than 1 and THAT is where I suspect things are tossing cookies. – Feloneous Cat Apr 20 '12 at 14:06
  • Another thing that helps in network applications is to run a packet sniffer (wireshark or even CocoaPacketAnalyzer) helps immensely. Then you don't have to guess why things aren't working. – Feloneous Cat Apr 20 '12 at 14:08

1 Answers1

-1

Try to check [serverUrl host] if it is nil.

I encountered this problem as well, so what I did was adding a http:// protocol string before the IP address (URLWithString:@"http://10.0.0.5").

Guntis Treulands
  • 4,764
  • 2
  • 50
  • 72
morph85
  • 807
  • 10
  • 18
  • He isn't using http protocol. So, no need to add http prefix. – fyasar Apr 06 '13 at 14:24
  • I was simply pointing out the mistake that there could be error in NSURL to be nil. (Reference: developer.apple.com/library/mac/#documentation/Cocoa/Reference/… section "Handling Object Creation Failure" where you will need to conform to RFC 2396 for file path or RFC 1808 for http URL and specify a scheme). Otherwise create CFString or NSString instead. If you're using CFURL or NSURL without scheme, there is high possibility you will be getting a nil. – morph85 Jun 30 '13 at 11:39