![]() |
IOS Streaming Browser 1.0
An IOS streaming browser to stream the display to others or to a projector
|
Public Member Functions | |
(id) | - initWithData:startOffset:maxLength:timeout:readLength:terminator:tag: |
(void) | - ensureCapacityForAdditionalDataOfLength: |
(NSUInteger) | - optimalReadLengthWithDefault:shouldPreBuffer: |
(NSUInteger) | - readLengthForNonTermWithHint: |
(NSUInteger) | - readLengthForTermWithHint:shouldPreBuffer: |
(NSUInteger) | - readLengthForTermWithPreBuffer:found: |
(NSInteger) | - searchForTermAfterPreBuffering: |
Data Fields | |
NSMutableData * | buffer |
NSUInteger | startOffset |
NSUInteger | bytesDone |
NSUInteger | maxLength |
NSTimeInterval | timeout |
NSUInteger | readLength |
NSData * | term |
BOOL | bufferOwner |
NSUInteger | originalBufferLength |
long | tag |
The GCDAsyncReadPacket encompasses the instructions for any given read. The content of a read packet allows the code to determine if we're:
Definition at line 596 of file GCDAsyncSocket.m.
- (void) ensureCapacityForAdditionalDataOfLength: | (NSUInteger) | bytesToRead |
Ensure the read buffer has the capacity for additional data param NSUInteger
Increases the length of the buffer (if needed) to ensure a read of the given size will fit. param NSUInteger
Definition at line 782 of file GCDAsyncSocket.m.
:(NSUInteger)bytesToRead { // Gets the read buffer size NSUInteger buffSize = [buffer length]; // Determines the amount of the buffer used by adding the buffer // offset plus the number of bytes that have been read so far for the read operation NSUInteger buffUsed = startOffset + bytesDone; // Computes the space available on the buffer by subtracting // the amount of the buffer used from the total buffer size NSUInteger buffSpace = buffSize - buffUsed; // If the bytes yet to read is greater than the buffer size then // increase the size of the buffer by the difference if (bytesToRead > buffSpace) { // Determine the size to increase the buffer NSUInteger buffInc = bytesToRead - buffSpace; // Increase the size of the read buffer [buffer increaseLengthBy:buffInc]; } }
- (id) initWithData: | (NSMutableData *) | d | |
startOffset: | (NSUInteger) | s | |
maxLength: | (NSUInteger) | m | |
timeout: | (NSTimeInterval) | t | |
readLength: | (NSUInteger) | l | |
terminator: | (NSData *) | e | |
tag: | (long) | i | |
param NSMutableData param NSUInteger param NSUInteger param NSTimeInterval param NSUInteger param NSData param long returns id
Initialize the GCDAsyncReadPacket param NSMutableData param NSUInteger param NSUInteger param NSTimeInterval param NSUInteger param NSData param long returns id
Definition at line 731 of file GCDAsyncSocket.m.
:(NSMutableData *)d startOffset:(NSUInteger)s // Number of characerts from the start maxLength:(NSUInteger)m // maximum length timeout:(NSTimeInterval)t // timeout for the packet readLength:(NSUInteger)l terminator:(NSData *)e tag:(long)i { if((self = [super init])) { bytesDone = 0; // number of bytes that have been read so far for the read operation maxLength = m; // set the maximum length of the read packet timeout = t; // set the read timeout readLength = l; // set the read length term = [e copy]; // set the terminator tag = i; if (d) // if there is mutable data passed-in to initialize the method then copy the buffer, set the offset and buffer length { // the read buffer buffer = [d retain]; startOffset = s; bufferOwner = NO; // if there is not a buffer owner originalBufferLength = [d length]; } else // if there is not mutable data { if (readLength > 0) { // Initialize the read buffer with a specific length buffer = [[NSMutableData alloc] initWithLength:readLength]; }else{ // If readLength is less than or equal to zero buffer = [[NSMutableData alloc] initWithLength:0]; } startOffset = 0; bufferOwner = YES; // If there is a buffer owner originalBufferLength = 0; } } return self; }
- (NSUInteger) optimalReadLengthWithDefault: | (NSUInteger) | defaultValue | |
shouldPreBuffer: | (BOOL *) | shouldPreBufferPtr | |
The optimal read length with a default value, and whether should prebuffer param NSUInteger param BOOL returns NSUInteger
This method is used when we do NOT know how much data is available to be read from the socket. This method returns the default value unless it exceeds the specified readLength or maxLength.
Furthermore, the shouldPreBuffer decision is based upon the packet type, and whether the returned value would fit in the current buffer without requiring a resize of the buffer. param NSUInteger param BOOL returns NSUInteger
Definition at line 819 of file GCDAsyncSocket.m.
:(NSUInteger)defaultValue shouldPreBuffer:(BOOL *)shouldPreBufferPtr { // Local variable for holding the result NSUInteger result; // If the length of the bytes in the packet is greater than zero if (readLength > 0) { // Read a specific length of data // Set the result to the lesser of the default value of bytes, or the length of the read packet less the bytes already read result = MIN(defaultValue, (readLength - bytesDone)); // There is no need to prebuffer since we know exactly how much data we need to read. // Even if the buffer isn't currently big enough to fit this amount of data, // it would have to be resized eventually anyway. // Whether should prebuffer the data if (shouldPreBufferPtr){ *shouldPreBufferPtr = NO; } } else // if readLength is equal to zero { // Either reading until we find a specified terminator, // or we're simply reading all available data. // // In other words, one of: // // - readDataToData packet // - readDataWithTimeout packet if (maxLength > 0) { result = MIN(defaultValue, (maxLength - bytesDone)); }else{ // if maximum length is not greater than zero result = defaultValue; } // Since we don't know the size of the read in advance, // the shouldPreBuffer decision is based upon whether the returned value would fit in the current buffer without requiring a resize of the buffer. // // This is because, in all likelyhood, the amount read from the socket will be less than the default value. // Thus we should avoid over-allocating the read buffer when we can simply use the pre-buffer instead. // Whether should pre-buffer if (shouldPreBufferPtr) { // Gets the buffer size NSUInteger buffSize = [buffer length]; // Get the amount of the buffer which has been utilized NSUInteger buffUsed = startOffset + bytesDone; // Gets the amount of available space in the bufer NSUInteger buffSpace = buffSize - buffUsed; // If the available space in the read buffer is larger than the default size than we don't need to prebuffer if (buffSpace >= result) { *shouldPreBufferPtr = NO; }else{ // if the available space in the read buffer is less than the default size than we need to prebuffer the request *shouldPreBufferPtr = YES; } } } // Returns the optimal read length return result; }
- (NSUInteger) readLengthForNonTermWithHint: | (NSUInteger) | bytesAvailable |
Reads length from data without a terminator param NSUInteger returns NSUInteger
For read packets without a set terminator, returns the amount of data that can be read without exceeding the readLength or maxLength.
The given parameter indicates the number of bytes estimated to be available on the socket, which is taken into consideration during the calculation.
The given hint MUST be greater than zero. param NSUInteger returns NSUInteger
Definition at line 903 of file GCDAsyncSocket.m.
:(NSUInteger)bytesAvailable { // Test whether there is a terminator NSAssert(term == nil, @"This method does not apply to term reads"); // Test if there are bytes available to read NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable"); // If the read packet has length if (readLength > 0) { // Read a specific length of data return MIN(bytesAvailable, (readLength - bytesDone)); // No need to avoid resizing the buffer. // If the user provided their own buffer, // and told us to read a certain length of data that exceeds the size of the buffer, // then it is clear that our code will resize the buffer during the read operation. // // This method does not actually do any resizing. // The resizing will happen elsewhere if needed. } else { // Read all available data // Get the number of bytes available to read NSUInteger result = bytesAvailable; // If the maximum length is set if (maxLength > 0) { // Get the lesser of the bytes available, or the maximum length minus the bytesDone reading or writing result = MIN(result, (maxLength - bytesDone)); } // No need to avoid resizing the buffer. // If the user provided their own buffer, // and told us to read all available data without giving us a maxLength, // then it is clear that our code might resize the buffer during the read operation. // // This method does not actually do any resizing. // The resizing will happen elsewhere if needed. return result; } }
- (NSUInteger) readLengthForTermWithHint: | (NSUInteger) | bytesAvailable | |
shouldPreBuffer: | (BOOL *) | shouldPreBufferPtr | |
Reads length of data which has a terminator param NSUInteger param BOOL returns NSUInteger
For read packets with a set terminator, returns the amount of data that can be read without exceeding the maxLength.
The given parameter indicates the number of bytes estimated to be available on the socket, which is taken into consideration during the calculation.
To optimize memory allocations, mem copies, and mem moves the shouldPreBuffer boolean value will indicate if the data should be read into a prebuffer first, or if the data can be read directly into the read packet's buffer. param NSUInteger (count of bytes available to read) param BOOL returns NSUInteger
Definition at line 963 of file GCDAsyncSocket.m.
:(NSUInteger)bytesAvailable shouldPreBuffer:(BOOL *)shouldPreBufferPtr { // Test whether the terminator is not nil NSAssert(term != nil, @"This method does not apply to non-term reads"); // Test whether there are bytes available to read NSAssert(bytesAvailable > 0, @"Invalid parameter: bytesAvailable"); // Gets teh number of bytes available to read NSUInteger result = bytesAvailable; // if the maximum length of the read packet is greater than zero if (maxLength > 0) { // Get the lesser of the result or the maximum length less the number of bytes read from the read operation result = MIN(result, (maxLength - bytesDone)); } // Should the data be read into the read packet's buffer, or into a pre-buffer first? // // One would imagine the preferred option is the faster one. // So which one is faster? // // Reading directly into the packet's buffer requires: // 1. Possibly resizing packet buffer (malloc/realloc) // 2. Filling buffer (read) // 3. Searching for term (memcmp) // 4. Possibly copying overflow into prebuffer (malloc/realloc, memcpy) // // Reading into prebuffer first: // 1. Possibly resizing prebuffer (malloc/realloc) // 2. Filling buffer (read) // 3. Searching for term (memcmp) // 4. Copying underflow into packet buffer (malloc/realloc, memcpy) // 5. Removing underflow from prebuffer (memmove) // // Comparing the performance of the two we can see that reading // data into the prebuffer first is slower due to the extra memove. // // However: // The implementation of NSMutableData is open source via core foundation's CFMutableData. // Decreasing the length of a mutable data object doesn't cause a realloc. // In other words, the capacity of a mutable data object can grow, but doesn't shrink. // // This means the prebuffer will rarely need a realloc. // The packet buffer, on the other hand, may often need a realloc. // This is especially true if we are the buffer owner. // Furthermore, if we are constantly realloc'ing the packet buffer, // and then moving the overflow into the prebuffer, // then we're consistently over-allocating memory for each term read. // And now we get into a bit of a tradeoff between speed and memory utilization. // // The end result is that the two perform very similarly. // And we can answer the original question very simply by another means. // // If we can read all the data directly into the packet's buffer without resizing it first, // then we do so. Otherwise we use the prebuffer. if (shouldPreBufferPtr) { // Gets the buffer size NSUInteger buffSize = [buffer length]; // Gets the amount of the buffer used by getting the offset and adding the number of bytes that have been read so far for the read operation NSUInteger buffUsed = startOffset + bytesDone; // Check if the buffer size is large enough to hold the result. If so, then we don't need to prebuffer if ((buffSize - buffUsed) >= result) { *shouldPreBufferPtr = NO; }else{ // If the buffer size is not large enough to hold the result, then pre-buffer *shouldPreBufferPtr = YES; } } // Returns the read length return result; }
- (NSUInteger) readLengthForTermWithPreBuffer: | (NSData *) | preBuffer | |
found: | (BOOL *) | foundPtr | |
Reads length of data which has a terminator but which is larger than the buffer so we need to prebuffer the data param NSData param BOOL return NSUInteger
For read packets with a set terminator,returns the amount of data that can be read from the given preBuffer,without going over a terminator or the maxLength.
It is assumed the terminator has not already been read.
param NSData param BOOL returns NSUInteger
Definition at line 1052 of file GCDAsyncSocket.m.
:(NSData *)preBuffer found:(BOOL *)foundPtr { // Test whether the terminator is not nil NSAssert(term != nil, @"This method does not apply to non-term reads"); // Test whether the prebuffer length is greater than zero NSAssert([preBuffer length] > 0, @"Invoked with empty pre buffer!"); // We know that the terminator, as a whole, doesn't exist in our own buffer. // But it is possible that a portion of it exists in our buffer. // So we're going to look for the terminator starting with a portion of our own buffer. // // Example: // // term length = 3 bytes // bytesDone = 5 bytes // preBuffer length = 5 bytes // // If we append the preBuffer to our buffer, // it would look like this: // // --------------------- // |B|B|B|B|B|P|P|P|P|P| // --------------------- // // So we start our search here: // // --------------------- // |B|B|B|B|B|P|P|P|P|P| // -------^-^-^--------- // // And move forwards... // // --------------------- // |B|B|B|B|B|P|P|P|P|P| // ---------^-^-^------- // // Until we find the terminator or reach the end. // // --------------------- // |B|B|B|B|B|P|P|P|P|P| // ---------------^-^-^- BOOL found = NO; // Get the length of the terminator NSUInteger termLength = [term length]; // Get the preBuffer length NSUInteger preBufferLength = [preBuffer length]; // Check if the bytes done plus prebuffer lengh is less than the // termination length. The bytes done is the number of bytes that have been read so far for the read operation if ((bytesDone + preBufferLength) < termLength) { // Not enough data for a full term sequence yet return preBufferLength; } // Maximum prebuffer length NSUInteger maxPreBufferLength; // If the maximum prebuffer length is greater than zero if (maxLength > 0) { // Gets the maximum prebuffer length maxPreBufferLength = MIN(preBufferLength, (maxLength - bytesDone)); // Note: maxLength >= termLength } // If the maximum prebuffer length is equal to or less than zero else { // Sets the maximum prebuffer length to the prebuffer length maxPreBufferLength = preBufferLength; } // the byte sequence Byte seq[termLength]; // Create a constant read only local attribute const void *termBuf = [term bytes]; // Buffer length NSUInteger bufLen = MIN(bytesDone, (termLength - 1)); void *buf = [buffer mutableBytes] + startOffset + bytesDone - bufLen; // Prebuffer length NSUInteger preLen = termLength - bufLen; void *pre = (void *)[preBuffer bytes]; // Set the loop count for searching through the buffer and prebuffer NSUInteger loopCount = bufLen + maxPreBufferLength - termLength + 1; // Plus one. See example above. // Prebuffer length NSUInteger result = preBufferLength; NSUInteger i; // Loop is the length of the buffer and pre-buffer for (i = 0; i < loopCount; i++) { // If there are bytes in the buffer if (bufLen > 0) { // Combining bytes from buffer and preBuffer // Copies bufLen bytes from the bufer to the seq memcpy(seq, buf, bufLen); // Copies preLen bytes from pre to seq plus bufLen memcpy(seq + bufLen, pre, preLen); // compare bytes in memory if (memcmp(seq, termBuf, termLength) == 0) { result = preLen; found = YES; break; } // Increases the buffer size buf++; // Decreases the buffer length bufLen--; // Increases the prebuffer length preLen++; } else // if buffer length is not greater than zero { // Comparing directly from preBuffer // compares byte string. Compares prebuffer with termBuf - both bytes are assumed to be termLength long. The memcmp function returns zero is the two byte strings are equal if (memcmp(pre, termBuf, termLength) == 0) { // Sets the prebuffer offset NSUInteger preOffset = pre - [preBuffer bytes]; // pointer arithmetic // Sets the result equal to the prebuffer offset plus the termLength (i.e. length of the terminator) result = preOffset + termLength; // Found the terminator in the prebuffer found = YES; break; } // Increments the prebuffer pre++; } } // There is no need to avoid resizing the buffer in this particular situation. if (foundPtr) { *foundPtr = found; } return result; }
- (NSInteger) searchForTermAfterPreBuffering: | (ssize_t) | numBytes |
Search for the terminator after prebuffering the data param ssize_t returns NSInteger
For read packets with a set terminator, scans the packet buffer for the term.
It is assumed the terminator had not been fully read prior to the new bytes.
If the term is found, the number of excess bytes after the term are returned.
If the term is not found, this method will return -1.
Note: A return value of zero means the term was found at the very en.
Prerequisites: The given number of bytes have been added to the end of our buffer. Our bytesDone variable has NOT been changed due to the prebuffered bytes.
param ssize_t returns NSInteger
Definition at line 1250 of file GCDAsyncSocket.m.
:(ssize_t)numBytes { // Test whether the terminator is not nil NSAssert(term != nil, @"This method does not apply to non-term reads"); // The implementation of this method is very similar to the above method. // See the above method for a discussion of the algorithm used here. void *buff = [buffer mutableBytes]; // The number of bytes that have been read so far for the read operation plus the number of bytes for prebuffering NSUInteger buffLength = bytesDone + numBytes; // Create a constant read only local attribute // Gets the size of the terminator const void *termBuff = [term bytes]; // Gets the length of the terminator NSUInteger termLength = [term length]; // Note: We are dealing with unsigned integers, // so make sure the math doesn't go below zero. NSUInteger i = ((buffLength - numBytes) >= termLength) ? (buffLength - numBytes - termLength + 1) : 0; // While the terimination length is less than or equal to the buffer length while (i + termLength <= buffLength) { void *subBuffer = buff + startOffset + i; // compare bytes in memory // Checks if the subBuffer equals the terminator buffer if (memcmp(subBuffer, termBuff, termLength) == 0) { // if the subBuffer and termBuffer are the same return buffLength - (i + termLength); } i++; } return -1; }
- (NSMutableData*) buffer |
read buffer
Definition at line 603 of file GCDAsyncSocket.m.
- (BOOL) bufferOwner |
whether there is a buffer owner
Definition at line 639 of file GCDAsyncSocket.m.
- (NSUInteger) bytesDone |
number of bytes that have been read so far for the read operation
Definition at line 613 of file GCDAsyncSocket.m.
- (NSUInteger) maxLength |
maximum length
Definition at line 618 of file GCDAsyncSocket.m.
- (NSUInteger) originalBufferLength |
original buffer length
Definition at line 644 of file GCDAsyncSocket.m.
- (NSUInteger) readLength |
read length
Definition at line 628 of file GCDAsyncSocket.m.
- (NSUInteger) startOffset |
start offset for read buffer
Definition at line 608 of file GCDAsyncSocket.m.
- (long) tag |
An application-defined integer or pointer that will be sent as an argument to the -socket:didReadData:withTag: message sent to the delegate.
Definition at line 649 of file GCDAsyncSocket.m.
terminator
Definition at line 634 of file GCDAsyncSocket.m.
- (NSTimeInterval) timeout |
the timeout value for reading from a host
Definition at line 623 of file GCDAsyncSocket.m.