【问题标题】:Stream to Get Data - NSInputStream流式获取数据 - NSInputStream
【发布时间】:2019-03-14 22:55:12
【问题描述】:

全部,

我有一个服务器,它有一个用于通信的 tcp 套接字流。我需要进入该流并读取它需要发送给我的初始数据。

我当前的代码如下。老实说,我完全是盲目的。我不确定这是否正确,更不用说适合这份工作了。

-(void) initNetworkCommunication
{
    //input stream
    NSInputStream *iStream;
    NSURL *url = [url initWithString:@"192.168.17.1:2004"];

    [iStream initWithURL:url];
    [iStream setDelegate:self];
    [iStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [iStream open];

}

所以在我看来,这段代码初始化了流,但是我如何从流中读取呢?

谢谢

【问题讨论】:

  • 代码块似乎没有正确分配NSInputStream 对象(即有一个init 但没有alloc)。

标签: iphone objective-c xcode nsstream


【解决方案1】:

有两种方法可以从流中获取数据:轮询和使用流事件。

轮询更简单,但会阻塞正在运行的线程。如果使用此方法,则无需执行setDelegate:scheduleInRunLoop:forMode: 调用。通过反复调用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

使用流事件需要设置委托并将流添加到运行循环。当某些事件发生时,包括当它接收数据时,流不会阻塞线程,而是向其委托发送stream:handleEvent: 消息。然后,委托可以从流中检索数据。这是一个示例stream:handleEvent: 方法:

- (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];
}

【讨论】:

  • 这对我们初学者来说是一个有价值的总结答案,值得编辑:就目前而言,通过调用 NSInputStream 的read:maxLength: inside if-stmt,你如果您成功获取流的内部缓冲区,将永远不会读取任何内容。但是我对这个主题不够扎实,无法自己编辑它——你能解决它吗?
  • P.S.我想知道为什么 NSOutputStream 没有等效的 getBuffer 方法?
  • @Wienke 在此示例中,对read:maxLength: 的调用只是将数据复制到在 if 语句中创建的临时缓冲区中。仅当您还没有包含数据的缓冲区时才需要执行此操作。在 if 语句之后,您应该立即添加代码来处理缓冲区中的数据,因为缓冲区只是临时的。 NSOutputStream 可能不提供对内部缓冲区的访问,因为它不允许访问您已经写入的数据,并且如果您直接写入缓冲区,它将无法知道它应该发送该数据。
  • 谢谢,我现在明白了。 (我在想内部缓冲区只是一个备用的空容器,您仍然需要调用read:maxlength 将数据放入其中。)
  • 你不应该在if (shouldClose)块中除了close之外还调用removeFromRunLoop吗?
【解决方案2】:

我想出了这个,基于其他一些答案。

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)))
        }

    }
}

【讨论】:

    猜你喜欢
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 2015-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-28
    相关资源
    最近更新 更多