Stream to Get Data - NSInputStream

前端 未结 2 2046
一生所求
一生所求 2020-12-30 16:10

All,

I have a server that has a tcp socket stream for communication. I need to get to that stream and read the initial data that it needs to send me.

My cur

相关标签:
2条回答
  • 2020-12-30 16:36

    I came up with this, based on some other answers.

    public enum StreamError: Error {
        case Error(error: Error?, partialData: [UInt8])
    }
    
    extension InputStream {
    
        public func readData(bufferSize: Int = 1024) throws -> Data {
            var buffer = [UInt8](repeating: 0, count: bufferSize)
            var data: [UInt8] = []
    
            open()
    
            while true {
                let count = read(&buffer, maxLength: buffer.capacity)
    
                guard count >= 0 else {
                    close()
                    throw StreamError.Error(error: streamError, partialData: data)
                }
    
                guard count != 0 else {
                    close()
                    return Data(bytes: data)
                }
    
                data.append(contentsOf: (buffer.prefix(count)))
            }
    
        }
    }
    
    0 讨论(0)
  • 2020-12-30 16:46

    There are two ways to get data from a stream: polling and using stream events.

    Polling is simpler, but will block the thread it is running in. If you use this method, you don't need to perform the setDelegate: or scheduleInRunLoop:forMode: calls. Polling is performed by repeatedly calling read:maxLength:.

    NSInteger result;
    uint8_t buffer[BUFFER_LEN]; // BUFFER_LEN can be any positive integer
    while((result = [iStream read:buffer maxLength:BUFFER_LEN]) != 0) {
        if(result > 0) {
            // buffer contains result bytes of data to be handled
        } else {
            // The stream had an error. You can get an NSError object using [iStream streamError]
        }
    }
    // Either the stream ran out of data or there was an error
    

    Using stream events requires setting the delegate and adding the stream to a run loop. Instead of blocking the thread, the stream will send a stream:handleEvent: message to its delegate when certain events occur, including when it receives data. The delegate can then retrieve the data from the stream. Here is an example stream:handleEvent: method:

    - (void)stream:(NSInputStream *)iStream handleEvent:(NSStreamEvent)event {
        BOOL shouldClose = NO;
        switch(event) {
            case  NSStreamEventEndEncountered:
                shouldClose = YES;
                // If all data hasn't been read, fall through to the "has bytes" event
                if(![iStream hasBytesAvailable]) break;
            case NSStreamEventHasBytesAvailable: ; // We need a semicolon here before we can declare local variables
                uint8_t *buffer;
                NSUInteger length;
                BOOL freeBuffer = NO;
                // The stream has data. Try to get its internal buffer instead of creating one
                if(![iStream getBuffer:&buffer length:&length]) {
                    // The stream couldn't provide its internal buffer. We have to make one ourselves
                    buffer = malloc(BUFFER_LEN * sizeof(uint8_t));
                    freeBuffer = YES;
                    NSInteger result = [iStream read:buffer maxLength:BUFFER_LEN];
                    if(result < 0) {
                        // error copying to buffer
                        break;
                    }
                    length = result;
                }
                // length bytes of data in buffer
                if(freeBuffer) free(buffer);
                break;
            case NSStreamEventErrorOccurred:
                // some other error
                shouldClose = YES;
                break;
        }
        if(shouldClose) [iStream close];
    }
    
    0 讨论(0)
提交回复
热议问题