1

現在ポートをリッスンしているソケットを閉じてから、そのソケットに戻ってポートでリッスンを再確立できるようにしたい。別のサーバーのリッスンソケットでの2番目のacceptOnPort呼び出しは常にエラー(アドレスはすでに使用されています)で終わるため、これを行うことはできません。リスニングソケットを閉じて新しいソケットを再確立するにはどうすればよいですか?

4

1 に答える 1

2

追加したばかりの問題 146を参照してください。

dispatch_source_set_event_handler は、GCDAsyncSocket 自身への参照を保持するブロックへの参照を保持するため、GCDAsyncSocket は割り当てを解除されません。

これにより、アドレスが既に使用されているため、GCDAsyncSocket リスナーを閉じてから再度開くことができなくなります。

これは、参照を弱い参照に変更することで解決できます。dispatch_source_set_event_handler の前に、次の行を追加します。

__weak GCDAsyncSocket* weakSelf = 自己;

次に、self の代わりに weakSelf を使用して doAccept を呼び出します。

while ([weakSelf doAccept:socketFD] && (++i < numPendingConnections));

これを 2 回繰り返す必要があります。1 回は ipv4 用、もう 1 回は ipv6 用です。

この時点で、dealloc が実行されるとすぐにクラッシュするため、GCDAsyncSocket が決して解放されないことが良いことであることがわかります。これは、dealloc が closeWithError を呼び出し、次に closeWithError がデリゲート socketDidDisconnect を呼び出し、GCDAsyncSocket 自身をパラメーターとして渡すためです。ARC は、GCDAsyncSocket が現在割り当て解除中であるためクラッシュする GCDAsyncSocket を即座に保持します。

これは、「delegate = nil」を dealloc の先頭に移動することで解決できます。これは、その時点でデリゲートを安全に呼び出すことができないのと同じように行うことができます (可能にしたい場合は不可能です)。 GCDAsyncSocket を渡しますが、これはもうできません)。この場合、代わりに socketDidDisconnect:nil を呼び出すこともできます。

いずれにせよ、socketDidDisconnect が呼び出されないか、適切な GCDAsyncSocket をパラメータとして呼び出されないことを意味します。これにより、API コントラクトが壊れる可能性がありますが、現時点では避けられません。

より良い API は、dealloc が発生する前に GCDAsyncSocket を強制終了するために、ある種の「Kill​​」メソッドを呼び出すことです。

于 2013-04-09T08:13:06.003 に答える