【发布时间】:2014-10-28 19:47:31
【问题描述】:
我正在尝试使用 GCDAsyncSocket 向我的 iDevice 客户端发送一些图像文件(大约 100MB)。
我想同步向客户端发送数据包。我的意思是在向第一个客户端发送 100MB 数据之后迭代到下一个客户端。但是由于 GCDAsyncSocket 的异步性质,我不知道如何序列化这些数据包发送。
我不能使用信号量,因为在发送图像之前,我会与每个客户协商以了解我应该发送哪些图像,然后尝试发送这些图像。而且我找不到一种巧妙的方法来等待信号量并发出信号。
- (void)sendImagesToTheClients:clients
{
...
//negotiating with client to know which images should sent
...
for(Client* client in clients)
{
packet = [packet addImages: images];
[self sendPacket:packet toClient:client];
}
}
- (void)sendPacket:packet toClient:client
{
// Initialize Buffer
NSMutableData *buffer = [[NSMutableData alloc] init];
NSData *bufferData = [NSKeyedArchiver archivedDataWithRootObject:packet];
uint64_t headerLength = [bufferData length];
[buffer appendBytes:&headerLength length:sizeof(uint64_t)];
[buffer appendBytes:[bufferData bytes] length:[bufferData length]];
// Write Buffer
[client.socket writeData:buffer withTimeout:-1.0 tag:0];
}
这就是 AsyncSocket 写入数据的工作原理:
- (void)writeData:(NSData *)data withTimeout:(NSTimeInterval)timeout tag:(long)tag
{
if ([data length] == 0) return;
GCDAsyncWritePacket *packet = [[GCDAsyncWritePacket alloc] initWithData:data timeout:timeout tag:tag];
dispatch_async(socketQueue, ^{ @autoreleasepool {
LogTrace();
if ((flags & kSocketStarted) && !(flags & kForbidReadsWrites))
{
[writeQueue addObject:packet];
[self maybeDequeueWrite];
}
}});
// Do not rely on the block being run in order to release the packet,
// as the queue might get released without the block completing.
}
那么我怎样才能同步这个任务呢?
更新
对于套接字连接,我使用GCDAsyncSocket,它大量使用委托进行事件通知。(GCDAsyncSocket.h 和 GCDAsyncSocket.m)(没有使用 completionHandler 的方法)。
我编写了一个名为 TCPClient 的类,它处理套接字连接和数据包发送,并将其设置为初始化套接字的委托。
写入数据包后,将调用委托方法- (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag。这只告诉我一些数据已被写入。在这里我无法根据书面数据决定调用dispatch_group_leave。所以依赖委托方法是没用的。
我在 GCDAsyncSocket.h 和 .m 文件中修改了 [client.socket writeData:buffer withTimeout:-1.0 tag:0] 以接受 completionBlock:[client.socket writeData:buffer withTimeout:-1.0 tag:0 completionBlock:completionBlock]
使用这种方法可以帮助我解决同步异步任务。
// perform your async task
dispatch_async(self.socketQueue, ^{
[self sendPacket:packet toClient:client withCompletion:^(BOOL finished, NSError *error)
{
if (finished) {
NSLog(@"images file sending finished");
//leave the group when you're done
dispatch_group_leave(group);
}
else if (!finished && error)
{
NSLog(@"images file sending FAILED");
}
}];
但问题是更新 GCDAsyncsocket 后,我的代码可能会中断。 在这里,我正在寻找一种巧妙的方法来将完成处理程序添加到 GCDAsyncsocket 而不直接修改它。比如围绕它创建一个包装器或者使用objective-c运行时的特性。 你有什么想法吗?
【问题讨论】:
标签: objective-c asynchronous grand-central-dispatch synchronous gcdasyncsocket