objective-c – NSOutputStream完成后关闭连接

objective-c – NSOutputStream完成后关闭连接,第1张

概述当NSOutputStream完成数据发送后,如何关闭连接? 搜索后我发现只有在服务器断开连接时才会调用事件NSStreamEventEndEncountered.不是如果OutputStream已完成要发送的数据. StreamStatus始终返回0(连接关闭)或2(连接打开)但从不返回4(写入数据). 由于上面提到的两种方法都没有告诉我有关写入过程的信息,我无法找到确定Stream是否仍在写入 当NSOutputStream完成数据发送后,如何关闭连接?

搜索后我发现只有在服务器断开连接时才会调用事件NsstreamEventEndEncountered.不是如果OutputStream已完成要发送的数据.

StreamStatus始终返回0(连接关闭)或2(连接打开)但从不返回4(写入数据).

由于上面提到的两种方法都没有告诉我有关写入过程的信息,我无法找到确定Stream是否仍在写入的方法,或者它是否已经完成并且我现在可以关闭连接.

经过5天的Googleling并尝试我完全没有想法…任何帮助表示赞赏.谢谢

根据要求编辑添加的代码:

- (voID)startSend:(Nsstring *)filePath{BOol                    success;NSURL *                 url;assert(filePath != nil);assert([[NSfileManager defaultManager] fileExistsAtPath:filePath]);assert( [filePath.pathExtension isEqual:@"png"] || [filePath.pathExtension isEqual:@"jpg"] );assert(self.networkStream == nil);      // don't tap send twice in a row!assert(self.fileStream == nil);         // ditto// First get and check the URL.............// If the URL is bogus,let the user kNow.  Otherwise kick off the connection.............if ( ! success) {    self.statusLabel.text = @"InvalID URL";} else {    // Open a stream for the file we're going to send.  We do not open this stream;     // NSURLConnection will do it for us.    self.fileStream = [NSinputStream inputStreamWithfileAtPath:filePath];    assert(self.fileStream != nil);    [self.fileStream open];    // Open a CFFTPStream for the URL.    self.networkStream = CFBrIDgingrelease(        CFWriteStreamCreateWithFTPURL(NulL,(__brIDge CFURLRef) url)    );    assert(self.networkStream != nil);    if ([self.usernameText.text length] != 0) {        success = [self.networkStream setProperty:self.usernameText.text forKey:(ID)kcfStreamPropertyFTPUsername];        assert(success);        success = [self.networkStream setProperty:self.passwordText.text forKey:(ID)kcfStreamPropertyFTPPassword];        assert(success);    }    self.networkStream.delegate = self;    [self.networkStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];    ///////******** liNE ADDED BY ME TO disONNECT FROM FTP AFTER CLOSING CONNECTION *********////////////    [self.networkStream setProperty:(ID)kcfBooleanFalse forKey:(ID)kcfStreamPropertyFTPAttemptPersistentConnection];    ///////******** END liNE ADDED BY ME *********////////////     [self.networkStream open];    // Tell the UI we're sending.    [self sendDIDStart];}}- (voID)stopSenDWithStatus:(Nsstring *)statusstring{if (self.networkStream != nil) {    [self.networkStream removeFromrunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];    self.networkStream.delegate = nil;    [self.networkStream close];    self.networkStream = nil;}if (self.fileStream != nil) {    [self.fileStream close];    self.fileStream = nil;}[self sendDIDStopWithStatus:statusstring];}- (voID)stream:(Nsstream *)aStream handleEvent:(NsstreamEvent)eventCode// An Nsstream delegate callback that's called when events happen on our // network stream.{#pragma unused(aStream)assert(aStream == self.networkStream);switch (eventCode) {    case NsstreamEventopenCompleted: {        [self updateStatus:@"Opened connection"];    } break;    case NsstreamEventHasBytesAvailable: {        assert(NO);     // should never happen for the output stream    } break;    case NsstreamEventHasspaceAvailable: {        [self updateStatus:@"Sending"];        // If we don't have any data buffered,go read the next chunk of data.        if (self.bufferOffset == self.bufferlimit) {            NSInteger   bytesRead;            bytesRead = [self.fileStream read:self.buffer maxLength:kSendBufferSize];            if (bytesRead == -1) {                [self stopSenDWithStatus:@"file read error"];            } else if (bytesRead == 0) {                [self stopSenDWithStatus:nil];            } else {                self.bufferOffset = 0;                self.bufferlimit  = bytesRead;            }        }        // If we're not out of data completely,send the next chunk.        if (self.bufferOffset != self.bufferlimit) {            NSInteger   bytesWritten;            bytesWritten = [self.networkStream write:&self.buffer[self.bufferOffset] maxLength:self.bufferlimit - self.bufferOffset];            assert(bytesWritten != 0);            if (bytesWritten == -1) {                [self stopSenDWithStatus:@"Network write error"];            } else {                self.bufferOffset += bytesWritten;            }        }    } break;    case NsstreamEventErrorOccurred: {        [self stopSenDWithStatus:@"Stream open error"];    } break;    case NsstreamEventEndEncountered: {        // FOR WHATEVER REASON THIS IS NEVER CALLED!!!!    } break;    default: {        assert(NO);    } break;}}
解决方法 您的问题可以有两种解释.如果您要问的是“我有一个NSOutputStream并且我已经写完了它,我该如何发出信号?”然后答案就像调用close方法一样简单.

或者,如果您真正说的是“我有一个NSinputStream并且我想知道何时到达流末尾”那么您可以查看hasBytesAvailable或streamStatus == NsstreamStatusAtEnd.

为了您的信息,要实际获取状态NsstreamStatusWriting,您需要在此线程调用write:maxLength:时从另一个线程调用streamStatus方法.

—编辑:代码建议

您永远不会得到通知的原因是输出流永远不会完成(除非它是固定大小的流,而不是FTP流).它是“完成”的输入流,此时您可以关闭输出流.这是你原来问题的答案.

作为进一步的建议,我将跳过运行循环调度和“事件处理”,除了处理输出流上的错误.然后我将读/写代码放入NSOperation子类并将其发送到NSOperationQueue.通过在该队列中保留对NSOperations的引用,您可以轻松取消它们,甚至可以通过添加percentComplete属性来显示进度条.我已经测试了下面的代码并且它有效.用FTP输出流替换我的内存输出流.您会注意到我已经跳过了验证,您当然应该保留这些验证.它们应该在NSOperation之外完成,以便更容易查询用户.

@interface NSSendfileOperation : NSOperation<NsstreamDelegate> {    NSinputStream  *_inputStream;    NSOutputStream *_outputStream;    uint8_t *_buffer;}@property (copy) Nsstring* sourcefilePath;@property (copy) Nsstring* targetfilePath;@property (copy) Nsstring* username;@property (copy) Nsstring* password;@end@implementation NSSendfileOperation- (voID) main{    static int kBufferSize = 4096;    _inputStream  = [NSinputStream inputStreamWithfileAtPath:self.sourcefilePath];    _outputStream = [NSOutputStream outputStreamToMemory];    _outputStream.delegate = self;    [_inputStream open];    [_outputStream open];    _buffer = calloc(1,kBufferSize);    while (_inputStream.hasBytesAvailable) {        NSInteger bytesRead = [_inputStream read:_buffer maxLength:kBufferSize];        if (bytesRead > 0) {            [_outputStream write:_buffer maxLength:bytesRead];            NSLog(@"Wrote %ld bytes to output stream",bytesRead);        }    }    NSData *outputData = [_outputStream propertyForKey:NsstreamDataWrittenToMemoryStreamKey];    NSLog(@"Wrote a total of %lu bytes to output stream.",outputData.length);    free(_buffer);    _buffer = NulL;    [_outputStream close];    [_inputStream close];}- (voID) stream:(Nsstream *)aStream handleEvent:(NsstreamEvent)eventCode{    // Handle output stream errors such as disconnections here}@endint main (int argc,const char * argv[]){    @autoreleasepool {        NSOperationQueue *sendQueue = [[NSOperationQueue alloc] init];        NSSendfileOperation *sendOp = [[NSSendfileOperation alloc] init];        sendOp.username = @"test";        sendOp.password = @"test";        sendOp.sourcefilePath = @"/Users/eric/bin/data/english-words.txt";        sendOp.targetfilePath = @"/Users/eric/Desktop/english-words.txt";        [sendQueue addOperation:sendOp];        [sendQueue waitUntilAllOperationsAreFinished];    }    return 0;}
@H_404_45@ 总结

以上是内存溢出为你收集整理的objective-c – NSOutputStream完成后关闭连接全部内容,希望文章能够帮你解决objective-c – NSOutputStream完成后关闭连接所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: https://www.outofmemory.cn/web/1022957.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存