Serguei Fedorov
Serguei Fedorov

Reputation: 7943

Sending over socket corrupted on other end

I have been dealing with the issue for a few days now and I cannot figure out what the issue is. I am trying to send a sound file over a socket from iOS to a C# based server. The code is as follows:

Objective C:

NSData * data = [NSData dataWithContentsOfFile:uri];

int length = 0;
int totalLen = [data length];
uint8_t buffer[1024];
Byte * readBytes = (uint8_t *)[data bytes];

//Tell the server what this is
int headerInt = 2;
NSData *header = [NSData dataWithBytes:&headerInt length:sizeof(int)];
[outputStream write:[header bytes] maxLength:sizeof(int)];
//Fill up the rest of the header (132 bytes total)
UTF8Char emptyHead[128];
[outputStream write:emptyHead maxLength:sizeof(char) * 128];

do
{
    int indexLen = (1024 > (totalLen - length) ? (totalLen- length) : 1024);
    memcpy(buffer, readBytes, indexLen);

    int written = [outputStream write: buffer maxLength: 1024];

    if (written < 0)
    {
        break;
    }

    length += written;


    readBytes += written;
}
while (length < [data length]);

[self sendENDS]; //Inform the server I am done

On the C# side for reading the data in (will try to shorten the code down), it is as follows:

        if (read > 0)
        {
            //Write this into an overall buffer
            obj.bufferStream.Write(obj.buffer, 0, read);
            obj.bufferStream.Flush();

            if (obj.buffer.Length > 4)
            {
                //Check if the client sent an "end of stream" flag
                byte[] checkBuff = obj.buffer.Skip(read - 4).Take(4).ToArray();
                string terminator = ASCIIEncoding.ASCII.GetString(checkBuff);
                if (terminator == "ENDS")
                {
                    obj.readMe = false;
                }
            }
            if (obj.readMe == true)
            {
                obj.buffer = new byte[ConnectionObject.bufferSize];//I keep forgetting to clear the buffer
                localSocket.BeginReceive(obj.buffer, 0, ConnectionObject.bufferSize, SocketFlags.None, new AsyncCallback(recieve), obj);
            }
        }
//...the rest takes care of taking the obj.streamBuffer and writing it into a file along with handling other types of requests

The issue that I have, is that I am sending over a .caf file recorded on the iPhone. However, when I try to play it back on the server machine, QuickTime tells me that the file cannot be played back. Also, the file size in bytes seems to be slightly shorter (about 20kb shorter) than the original. Any ideas? I apologize for throwing so much code up. Any help is greatly appreciated!

PS. The connection is open correctly and sending data the other way around works perfectly.

Upvotes: 0

Views: 243

Answers (2)

Serguei Fedorov
Serguei Fedorov

Reputation: 7943

As it turns out that while Davyd is very much correct, the actual issue was in the buffer sizes not properly set up. I had a blank in front of the bytes file which caused issues in reading it. Align your buffers/socket read right next time :)

Upvotes: 0

Davyd Geyl
Davyd Geyl

Reputation: 4623

You need to write to the stream only if it has space available rather then assuming is is always ready. Implement delegate method:

[_ostream setDelegate:self];
[_ostream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[_ostream open];


- (void)stream:(NSStream*)aStream handleEvent:(NSStreamEvent)event
{
    switch (event)
    {
        ...
        case NSStreamEventHasSpaceAvailable:
        {
            NSInteger written = [_ostream write:buffer maxLength:1024];
            ...

            if (transferredDataLength == dataLength])
            {
                [_ostream close];
                [_ostream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
                _ostream = nil;
            }
        }
        ...
    }
}

You may need to process other events such as NSStreamEventErrorOccurred, NSStreamEventEndEncountered, etc.

Upvotes: 1

Related Questions