2011-01-25 2 views
1

특정 멀티 캐스트 그룹에 가입되어있는 모든 사람에게 멀티 캐스트 "Hello"패킷을 보낸 다음 모든 응답을 수신하는 C# .Net 3.5 응용 프로그램이 있습니다. 따라서 X 초마다 "Hello"패킷을 보내고 응답하는 모든 사람을 기록 할 수 있습니다.비동기 소켓 작업 취소

는 다음과 같이 사용하기위한 것입니다 : 비동기 읽기를 취소

MulticastHello hello_ = new MulticastHello(); 

// alert our UI of any responses to the 'Hello' 
hello_.ReceivedHelloResponse += OnHelloResponse; 

// this timer function is triggered every X seconds 
private void OnTimer(object sender, EventArgs e) 
{ 
    // stop listening for responses to the last 'hello' 
    hello_.CancelHello(); 

    // send a new 'hello' and start listening for responses 
    hello_.SendHello("224.0.100.1"); 
} 

불행하게도, 나는 데 문제. 내 private void OnReceive(IAsyncResult ar) 함수는 때때로 "IAsyncResult 개체가이 클래스의 해당 비동기 메서드에서 반환되지 않았습니다"라는 System.ArgumentException을 throw합니다.

비동기 소켓 작업을 어떻게 안정적으로 취소 할 수 있습니까? 아니면 이것을하는 더 좋은 방법이 있습니까?

내 구현은 다음과 같습니다.

감사합니다, PaulH

public class HelloResponseEventArgs : EventArgs { /*...*/ } 

public class MulticastHello : IDisposable 
{ 
    public event EventHandler<HelloResponseEventArgs> ReceivedHelloResponse; 

    private Socket socket_; 

    private byte[] received_ = new byte[HelloResponse.Size]; 

    private EndPoint responder_ = new IPEndPoint(IPAddress.Any, 0); 

    protected virtual void OnReceivedHelloResponse(HelloResponseEventArgs e) 
    { 
     EventHandler<HelloResponseEventArgs> evt = ReceivedHelloResponse; 
     if (null != evt) 
      evt(this, e); 
    } 

    private void OnReceive(IAsyncResult ar) 
    { 
     IPEndPoint ipendpoint = new IPEndPoint(IPAddress.Any, 0); 
     EndPoint endpoint = ipendpoint as EndPoint; 

     try 
     { 
      socket_.EndReceiveFrom(ar, ref endpoint); 
     } 
     catch (System.ObjectDisposedException) 
     { 
      // the read was canceled. This is expected. 
      return; 
     } 

     // decode the response and set the event 
     IPEndPoint remote = endpoint as IPEndPoint; 
     HelloResponse response = new HelloResponse(Deserialize<HelloPacket>(received_)); 
     OnReceivedHelloResponse(new HelloResponseEventArgs(remote.Address.ToString(), response)); 

     // keep receiving responses until canceled 
     socket_.BeginReceiveFrom(received_, 
      0, 
      received_.Length, 
      SocketFlags.None, 
      ref endpoint, 
      new AsyncCallback(OnReceive), 
      null); 
    } 

    // stop listening for responses to the hello frame 
    public void CancelHello() 
    { 
     if (socket_ != null) 
      socket_.Close(); 
    } 

    // send an initial 'Hello' to the a multicast address. Start listening for responses 
    public void SendHello(string address) 
    { 
     socket_ = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); 
     socket_.MulticastLoopback = false; 
     socket_.Ttl = 255; 

     HelloResponse send = new HelloResponse(); 
     byte[] data = Serialize(send.Packet); 

     EndPoint remote = new IPEndPoint(IPAddress.Parse(address), 7); 
     socket_.SendTo(data, remote); 

     socket_.BeginReceiveFrom(received_, 
      0, 
      received_.Length, 
      SocketFlags.None, 
      ref responder_, 
      new AsyncCallback(OnReceive), 
      null); 
    } 

    #region IDisposable Members 
    /* close the socket on dispose*/ 
    #endregion 
} 

답변

2

Close() 기다리지 않습니다. 즉시 종료됩니다. EndReceiveFrom()이 끝나기 전에 다음 SendHello()가 오면 System.ArgumentException을 던집니다.

System.ObjectDisposedExceptionOnReceive에 잡힐 때 설정된 Close() 호출 후에 이벤트 개체를 기다리는 것이 해결책입니다.

-PaulH

3

BeginReceive에서 상태 인수로 소켓을 보냅니다. 나는.

socket_.BeginReceiveFrom(
     received_, 
     0, 
     received_.Length, 
     SocketFlags.None, 
     ref endpoint, 
     new AsyncCallback(OnReceive), 
     socket_); 

그런 다음 OnReceive에서 클래스 변수 socket 대신이를 사용하십시오. 나는.

이렇게하면 BeginReceive가 호출 된 동일한 소켓에서 EndReceiveFrom 호출이 발생합니다. 그런 다음 PaulH는 OnReceive에서 Close()가 소켓에서 호출 된 신호가 될 ObjectDisposedException을 잡는 것에 대해 언급합니다.

-Oli