在后台线程上执行工作后写入 NSOutputStream 不起作用
Writes to NSOutputStream after performing work on background thread don't work
我有一个程序在一些初始处理后通过 NSStreams 发送大文件。申请流程如下:
1) 两个设备相互连接,打开它们的输入和输出流,并安排它们的 运行 循环:
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];
[self.inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[self.outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[self.inputStream open];
[self.outputStream open];
2) 服务器设备向客户端发送一条消息,指示一切正常,我们已准备就绪。客户端收到这条消息就好了。
3) 客户端然后选择要发送到服务器的文件列表并点击 "send." 客户端然后关闭后台线程以获取一堆文件并将它们全部压缩。这可能需要一分钟左右的时间。
- (void) sendFilesAtPaths: (NSArray *) paths
{
self.paths = [paths copy];
__weak FileSharingClient *weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for(Item *item in weakSelf.paths)
{
//Zip files up, this can take some time but we're on a background thread so it won't lock up the UI
[weakSelf.connection zipFilesAssociatedWithItem:item];
}
//Now that we've done all the heavy work, bounce back to the main thread to actually start sending the data
dispatch_async(dispatch_get_main_queue(), ^{
//Start by sending only the first file, the server will let us know when they are ready for the next one
[weakSelf.connection sendFileWithItem:weakSelf.paths.firstObject];
});
});
}
4) 对 'sendFileWithItem:' 的调用通过以下调用传递第一条信息:
if([_outputStream hasSpaceAvailable])
{
NSInteger written = [self.outputStream write:buffer maxLength:self.outputHeaderSize];
}
以下所有数据都是通过调用 - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)streamEvent
发送数据来传输的
问题
我在这里看到的问题是,如果压缩这些文件的后台线程需要更长的时间,写入数据的初始调用确实表明字节已写入流,但我从未收到- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)streamEvent
的任何调用。服务器从不接收信息。大约 30 秒后,写入命令(我假设?)超时,客户端收到一个空字符串(不是我从服务器明确发送的),并且客户端的连接关闭。
如果我发送一个不需要很长时间就能压缩的文件,我不会发现这个问题。
运行 主线程上的所有内容 - 包括压缩过程 - 都没有解决问题(即使忽略它锁定 UI 的事实)。这似乎排除了线程问题,但这就是我现在必须继续的。
完全没有思路,希望有人能帮帮我。
注意:考虑到这个建议,我无法使用 CocoaAsyncSockets 库。
以防万一有人偶然发现了这个并且恰好看到了我看到的同样的东西(并且认为同样的事情是问题所在):
问题不在于线程导致问题 - 只是写 post 让我意识到我是多么荒谬。问题似乎是底层 TCP 套接字在等待接收数据太长时间后超时。我通过每秒发送一次心跳消息解决了这个问题,这使套接字保持活动状态,直到我准备好真正开始发送数据。
我有一个程序在一些初始处理后通过 NSStreams 发送大文件。申请流程如下:
1) 两个设备相互连接,打开它们的输入和输出流,并安排它们的 运行 循环:
[self.inputStream setDelegate:self];
[self.outputStream setDelegate:self];
[self.inputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[self.outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
[self.inputStream open];
[self.outputStream open];
2) 服务器设备向客户端发送一条消息,指示一切正常,我们已准备就绪。客户端收到这条消息就好了。
3) 客户端然后选择要发送到服务器的文件列表并点击 "send." 客户端然后关闭后台线程以获取一堆文件并将它们全部压缩。这可能需要一分钟左右的时间。
- (void) sendFilesAtPaths: (NSArray *) paths
{
self.paths = [paths copy];
__weak FileSharingClient *weakSelf = self;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for(Item *item in weakSelf.paths)
{
//Zip files up, this can take some time but we're on a background thread so it won't lock up the UI
[weakSelf.connection zipFilesAssociatedWithItem:item];
}
//Now that we've done all the heavy work, bounce back to the main thread to actually start sending the data
dispatch_async(dispatch_get_main_queue(), ^{
//Start by sending only the first file, the server will let us know when they are ready for the next one
[weakSelf.connection sendFileWithItem:weakSelf.paths.firstObject];
});
});
}
4) 对 'sendFileWithItem:' 的调用通过以下调用传递第一条信息:
if([_outputStream hasSpaceAvailable])
{
NSInteger written = [self.outputStream write:buffer maxLength:self.outputHeaderSize];
}
以下所有数据都是通过调用 - (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)streamEvent
问题
我在这里看到的问题是,如果压缩这些文件的后台线程需要更长的时间,写入数据的初始调用确实表明字节已写入流,但我从未收到- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)streamEvent
的任何调用。服务器从不接收信息。大约 30 秒后,写入命令(我假设?)超时,客户端收到一个空字符串(不是我从服务器明确发送的),并且客户端的连接关闭。
如果我发送一个不需要很长时间就能压缩的文件,我不会发现这个问题。
运行 主线程上的所有内容 - 包括压缩过程 - 都没有解决问题(即使忽略它锁定 UI 的事实)。这似乎排除了线程问题,但这就是我现在必须继续的。
完全没有思路,希望有人能帮帮我。
注意:考虑到这个建议,我无法使用 CocoaAsyncSockets 库。
以防万一有人偶然发现了这个并且恰好看到了我看到的同样的东西(并且认为同样的事情是问题所在):
问题不在于线程导致问题 - 只是写 post 让我意识到我是多么荒谬。问题似乎是底层 TCP 套接字在等待接收数据太长时间后超时。我通过每秒发送一次心跳消息解决了这个问题,这使套接字保持活动状态,直到我准备好真正开始发送数据。