2011-01-11 2 views
33

당연히 데이터가 없으면 BeginReceive()은 끝나지 않을 것입니다. MSDN suggestsClose()을 호출하면 BeginReceive()이 중단됩니다.소켓의 BeginReceive()를 중단하는 방법은 무엇입니까?

그러나, 소켓 Close()를 호출하면 this great ansewr에 파악하고, 그 결과 개체가 이미 설치되어 있기 때문에 EndReceive()가 예외를 슬로우로, 그것에 Dispose()을 수행합니다 (그리고 않습니다!).

어떻게해야합니까?

+0

http://stackoverflow.com/questions/1921611/c-how-do-i-terminate-a-socket-before-socket-beginreceive-calls-back – SwDevMan81

답변

40

이것은 (매우 멍청한) 디자인에 의한 것 같습니다. 이 예외가 발생하여 코드에 포착되어 있어야합니다. ,

는 BeginConnect에 대기중인 호출을 취소하려면() 메소드 :

MSDN 실제로 그것에 대해 침묵 보이지만 다른 비동기 소켓 방식, BeginConnect()의 문서를 보면, 우리가 무엇을 발견입니다 소켓을 닫습니다. 비동기 작업 이 진행되는 동안 Close() 메서드가 일 때 호출되면을 BeginConnect() 메서드에 제공하는 콜백은 이라고합니다. 다음에 EndConnect (IAsyncResult) 메서드를 호출하면 에 에 ObjectDisposedException을 throw하면 작업이 취소되었음을 나타내며 이 취소되었습니다.

BeginConnect에 대한 올바른 방법은 BeginReceive에도 해당됩니다. 이것은 사용자가 반드시 던져 버리고 예외를 캐치하여 정상적인 흐름의 일부로 디버거를 괴롭히는 결과를 낳기 때문에 Microsoft의 비동기 API 부분에서는 분명히 형편없는 디자인입니다. Close()는 처음부터 작업을 완료하기 때문에 작업이 완료 될 때까지 "대기"할 수있는 방법이 없습니다.

+4

이렇게 작동하도록 만들어졌지만 그것은 내가 생각하는 것입니다. – Kelly

+0

@Kelly : 디자인으로 잘못 되었나요? 'EndReceive'를 호출하는 코드는 예외가 발생했는지 여부에 관계없이 실패를 처리해야합니다. 조건이'EndReceive'에서 바로 처리 될 수 있다면, 예외를 던지 지 않고'catch'가'if'로 대체 될 수 있지만, 처리 할 수 ​​없다면' if ([failed]) throw [something]'하고 catch를 필요로합니다. 연결을 예외로 사용하는 경우 성능 오버 헤드가 발생하기에 충분히 자주 중단되면 안됩니다. – supercat

+4

'예외적 인'흐름과 달리 일반 입력의 일부로 예외를 던지고 잡는 것은 성능에 상관없이 나쁜 디자인입니다. 또한 종종 유용하게 사용되는 "break on throw"설정 아래에서 디버깅을 방해 할 수 있습니다. –

-1

다른 해결책은 다른 포트에 바인딩 된 소켓을 사용하여 "사용자"에게 "제어 메시지"를 보내는 것입니다. 정확히 중단되지는 않지만 비동기 작업이 종료됩니다.

+0

대기 핸들 또는 이벤트를 사용할 수도 있습니다. 또한 대답에 나와있는 옵션을 사용할 수도 있습니다. 클라이언트와 서버마다 다른 소켓이 필요합니다. – Jay

-1

이것도 문제가 아니지만 .BeginReceive()을 호출하기 전에 간단한 부울 플래그를 사용하여 알 수 있습니다 (예외 처리가 필요하지 않음). 이미 시작/중지 처리가 있었기 때문에이 수정은 if 문 하나였습니다 (OnReceive() 메서드의 맨 아래로 스크롤).

if (_running) 
{ 
    _mainSocket.BeginReceive(_data, 0, _data.Length, SocketFlags.None, OnReceive, null); 
}     

이 접근법을 간과해야할까요?

+0

BeginReceive를 호출 한 후 중단하려는 경우에는 작동하지 않습니다. BeginReceive가 비동기 콜백을 생성하면 수신 할 데이터가있을 때까지 비동기 콜백 대기 상태가됩니다. BeginReceive를 호출 한 후 Async 콜백이 실행되기 전에 중단하려는 경우 (이는 그의 질문에서 제안하는 것입니다)? 이 경우 솔루션이 작동하지 않습니다. –

+0

따라서 비동기 콜백을 중단하는 유일한 방법은 소켓을 닫는 것만 큼 OP의 경우 예외 처리가 필요합니다. EndReceive에서 ObjectDisposedException을 발생시킵니다. –

2

나는 SocketOptions를 사용하는 것이 좋습니다.

스택에 보내기 또는 받기 작업이 있으면 스택의 소켓 옵션에 바인딩됩니다.

작은 보내기 또는 받기 제한 시간을 사용하여 작업 전에 사용하면 동일한 작업 중에 변경된 시간이 짧거나 길어도 상관 없습니다.

더 많은 컨텍스트 전환이 발생하지만 모든 프로토콜에서 소켓을 닫을 필요는 없습니다.예를 들어

:

1)에서 소규모 초과

2) 동작

3) 설정 초과 큰 수행

이 차단 = 거짓을 사용뿐만 자동으로 비슷 지정한 제한 시간.

+1

소켓 보내기/받기 제한 시간 옵션은 차단 I/O 작업이 진행되는 동안에 만 적용됩니다. 프레임 워크의 비동기 I/O가 어떻게 구현되는지는 보지 못했지만 WSASelect 또는 I/O 완료 포트와 같은 실제 비동기 메커니즘이 필요하고 차단 작업에있는 일부 스레드가 아닌 것으로 기대하고 있습니다. –

0

TCP 소켓 연결의 경우 액세스를 시도하기 전에 소켓의 상태를 확인하기 위해 Connected 속성을 사용할 수 있습니다 폐기 된 모든 방법. MSDN :

"Connected 속성은 마지막 I/O 작업에서 Socket의 연결 상태를 가져오고 false를 반환하면 Socket이 절대로 연결되지 않았거나 더 이상 연결되어 있지 않습니다."

"더 이상 연결되어 있지 않습니다"라는 말은 이전에 소켓에서 Close()가 호출되었음을 의미합니다. 수신 콜백 시작시 소켓이 Connected인지 여부를 확인하면 예외는 없습니다.

+1

이러한 비동기 소켓이 다중 스레드 프로그램 내에 있다는 것을 알고 있습니까? 스레드 A에서 한 행을 검사하면 실행이 스레드 B에서 닫히고 스레드 A에서 다시 닫히고 조건이 창 밖으로 나옵니다. –

관련 문제