xcode 流获取数据 - NSInputStream

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/6685785/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 21:28:25  来源:igfitidea点击:

Stream to Get Data - NSInputStream

iphoneobjective-cxcodensstream

提问by Baub

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.

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

My current code is as follows. To be honest, I'm going at this completely blind. I'm not sure if this is correct let alone the right thing for the job.

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

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

}

So from the way I see it, this code initializes the stream, but how do I read from the stream?

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

Thanks

谢谢

回答by ughoavgfhw

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:.

轮询更简单,但会阻塞它正在运行的线程。如果使用此方法,则不需要执行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

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:

使用流事件需要设置委托并将流添加到运行循环中。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];
}

回答by Mark Bridges

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

    }
}