Hi
I've been experimenting with BSD sockets for use in a MySQL connector class and have hit a wall. The short version is that MySQL returns query results in chunks and nothing I try seems to be able to get all the data. Performing read on a file descriptor whether inside a loop or out, only reads up to a maximum of 1448 bytes. There is never any additional data available and subsequent reads always block. I've studied numerous tutorials online using both kqueues and simpler while loops to try to get more data but nothing seems to work. I thought kqueues were the way to go, but all I ever get is reads of exactly 1 byte. The queue never detects any other data even though I know for a fact that the MySQL server is sending many thousands of bytes.
Here's what I've tried so far:
Method 1: - Works perfectly if sender and receiver are on the same machine - Works partially if sender and receiver are on different machines so long as the result data is <= 1448 bytes - For data larger than 1448 bytes, reads first 1448 bytes and stops. No other data ever becomes available on the socket
NOTE: readBuffer is 4096 bytes
- (NSData *) reply { NSMutableData *result = [NSMutableData data]; int readBytes = readBufferLength;
while (readBytes == readBufferLength) { readBytes = read(socketFD, readBuffer, readBufferLength);
NSLog(@"readBytes: %i", readBytes);
// append buffer's data to result if (readBytes > 0) [result appendBytes: readBuffer length: readBytes]; else { // some sort of error occurred, log it, // release result and break out of the loop NSLog(@"error: %@", [MySQLSocket socketError]);
[result release]; result = nil;
break; } }
return result; }
Method 2: - Reads exactly 1 byte and never detects more data on the socket
- (NSData *) reply { NSMutableData *result = [NSMutableData data];
struct kevent conditions, event;
struct timespec timeout = { 1, 0 }; // seconds, nanoseconds
int queue = kqueue(), eventCount, readBytes, totalBytes;
BOOL notDone = YES;
// Set up the conditions we're interested in (data available for reading) EV_SET(&conditions, socketFD, EVFILT_READ, EV_ADD , 0, 4, NULL);
while (notDone) { eventCount = kevent(queue, &conditions, 1, &event, 1, &timeout);
NSLog(@"eventCount: %i", eventCount);
if ((eventCount == MYSQL_INVALID_READ_LENGTH) || (event.flags & EV_EOF)) { NSLog(@"Error: socket closed"); break; } else if (event.data > 0) { // read data from file descriptor
readBytes = read(socketFD, readBuffer, readBufferLength); totalBytes += readBytes;
NSLog(@"eventCount: %1, bytesRead: %i", eventCount, readBytes);
// append buffer's data to result if (readBytes > 0) [result appendBytes: readBuffer length: readBytes]; } }
if (queue != MYSQL_INVALID_READ_LENGTH) close(queue);
return result; }
What's the trick to read all data from a socket?
Thanks for any help
|