GCDAsyncSocket을 사용하여 iDevice 클라이언트로 일부 이미지 파일 (거의 100MB)을 보내려고합니다.Objective-C의 비동기 작업을 동기화하십시오.
내가 원하는 동 기적으로은 클라이언트에 패킷을 보냅니다. 첫 번째 클라이언트에 100MB의 데이터를 보낸 후 다음 클라이언트로 반복합니다. 그러나 비동기식 GCDAsyncSocket의 성격이 패킷 보내기를 어떻게 serialize 할 수 있는지 알지 못합니다.
이미지를 보내기 전에 어떤 이미지를 보내야하는지 알기 위해 각 클라이언트와 협상하기 때문에 세마포어를 사용할 수 없습니다. 세마포어를 기다리고 신호를 보낼 수있는 깔끔한 방법을 찾을 수 없습니다.
- (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.
}
그래서 사람이 어떤 생각을 가지고 않습니다 어떻게이 작업을 동기화 할 수 있습니다
:- (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 쓰기 데이터가 어떻게 작동?
소켓 연결에 대한
UPDATE 내가 많이 이벤트 알림에 대한 위임을 사용 GCDAsyncSocket. (GCDAsyncSocket.h 및 GCDAsyncSocket.m) (completionHandler와 방법 없음)를 사용합니다.
소켓 연결과 패킷 보내기를 처리하고 초기화 된 소켓의 대리자로 설정하는 TCPClient라는 클래스를 작성했습니다. 패킷을 작성한 후 대리자 메서드 - (void)socket:(GCDAsyncSocket *)sock didWriteDataWithTag:(long)tag
이 호출됩니다. 그것은 어떤 데이터가 쓰여졌다는 것을 알려주는 것입니다. 여기서 나는 서면 자료를 근거로하여 dispatch_group_leave
으로 전화를 할 수 없다. 그래서 위임 메서드를 사용하는 것은 쓸모가 없습니다.
내가 수정 한 [client.socket writeData는을 : -1.0 태그 : withTimeout 버퍼 0] GCDAsyncSocket.h와하는 .m 파일에 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 런타임의 기능을 사용하는 것과 같습니다. 의견이 있으십니까?
'- (무효) writeData는 (을 NSData *) 데이터 withTimeout (NSTimeInterval) 초과 태그 : (long) tag'는'GCDAyncSocket.m'에있는 메소드이고 그것을 수정해서는 안됩니다. socketQueue를'GCDAsynSocket'에 전달할 수 있습니다. 다른 dispatch_async를 만들어서'sendPacket : client :'를 넣고'dispatch_group_leave (group); '를 호출해야합니까? 왜냐하면 내가 한 것이지만 아무것도 바뀌지 않았다. 여전히 비동기입니다. –
'GCDAsyncSocket'은 위임을 통해 완료를 알립니다 callBack'didWriteDataWithTag : '문제는이 메소드가 데이터를 기반으로 작성된 데이터를 보내지 않습니다 (이미지 일 경우)'dispatch_group_leave (group);'입니다. GCDAsyncSocket은 completionHandler를 통해 나를 알리지 않습니다. –
이 라이브러리의 위임 된 특성을 반영하여 질문을 업데이트하십시오.나는 내 대답을 업데이트 할 것이고, 당신은 delegate 메쏘드에'dispatch_group_leave'를 넣을 수있다. – thelaws