현재 포트를 수신 대기중인 소켓을 닫고 다시 포트로 수신 대기하도록 설정할 수 있습니다. 다른 서버 청취 소켓의 두 번째 acceptOnPort 호출이 항상 오류 (주소가 이미 사용 중임)로 끝나기 때문에이를 수행 할 수 없습니다. 청취 소켓을 닫고 새 소켓을 다시 설정할 수 있습니까?GCDAsyncSocket은 연결을 해제 한 후에도 한 번만 OpenPort를 수락 할 수 없습니다.
답변
방금 추가 한 issue 146을 참조하십시오.
GCDAsyncSocket은 dispatch_source_set_event_handler가 GCDAsyncSocket 자체에 대한 참조를 보유하고있는 블록에 대한 참조를 보유하기 때문에 절대 할당을 해제하지 않습니다.
이렇게하면 주소가 이미 사용 중이므로 GCDAsyncSocket 수신기를 닫았다가 다시 열 수 없게됩니다.
약한 참조에 대한 참조를 변경하면 해결할 수 있습니다. dispatch_source_set_event_handler 앞에 다음 줄을 추가하십시오.
__weak GCDAsyncSocket * weakSelf = self;
그런 다음 self 대신 doAccept를 호출하여 weakSelf를 사용하십시오.
while ([weakSelf doAccept : socketFD] & & (++ i < numPendingConnections));
ipv4의 경우 한 번, ipv6의 경우 한 번 두 번 반복해야합니다.
이 시점에서, dealloc가 즉시 실행되기 때문에 GCDAsyncSocket이 결코 할당 취소되지 않는 것이 좋습니다. 이는 dealloc이 closeWithError를 호출하고, 이는 delegate socketDidDisconnect를 호출하고 GCDAsyncSocket 자체를 매개 변수로 전달하기 때문입니다. ARC는 GCDAsyncSocket이 현재 할당 해제 될 때 즉시 충돌하는 GCDAsyncSocket을 유지합니다.
"delegate = nil"을 dealloc의 시작 부분으로 이동하면 해결할 수 있습니다.이 시점에서 대리인을 안전하게 호출 할 수 없기 때문에 가능합니다. (원한다면 불가능합니다. 더 이상 할 수없는 GCDAsyncSocket을 전달할 수 있습니다. 대안은이 경우 socketDidDisconnect : nil을 호출하는 것입니다.
어느 쪽이든 socketDidDisconnect가 호출되지 않거나 해당 GCDAsyncSocket을 매개 변수로 사용하여 호출되지 않아 API 계약을 위반할 수 있지만이 시점에서는 불가 피할 수 없음을 의미합니다.
더 나은 API는 dealloc이 발생하기 전에 GCDAsyncSocket을 종료하는 일종의 "Kill"메서드 호출을 갖는 것입니다.
내가 제안한 __weak 변경을 만들었으며 두 번째로 AcceptOnPort를 시도 할 때 여전히 오류가 발생합니다. 내가 놓친 게 있니? – Boon
피터, 후속 acceptOnPort에서 약간의 지연을 도입하면 제안이 작동합니다. 고맙습니다! – Boon