2012-03-06 34 views
1

나는 C#에서 소켓 프로그래밍을 다루고있다. 주어진 프로토콜로 서버와 통신하는 클라이언트 애플리케이션을 빌드해야합니다.비동기 소켓 클라이언트가 수신

성공적으로 비동기 전송 메소드를 구현했지만 수신 알고리즘을 구현하는 데 문제가 있습니다. 동기식 수신 방법이 정상적으로 작동합니다.

먼저 수신 메시지를 읽고 ACK해야합니다. 올바른 모든 수신 메시지에는 종결 자 (0x0c)가 있어야합니다.

3 개의 스레드로 구성된 MessageFlow라는 멀티 스레딩 클래스를 작성했습니다. 하나는 메시지 전송을 담당하고 다른 하나는 메시지 수신을 담당하고, 나머지 하나는 메시지를 처리합니다. 받은 메시지를 해석하고 뭔가를하십시오.

수신 스레드에 대한 작업자의 기능이

private void ReadSocketWorker() 
{ 
    while (this.canRun) 
    { 
    xComClient.Receive(); 
    xComClient.receiveDone.WaitOne(); 
    Thread.Sleep(10); 
    } 
} 

XComClient처럼 내 클래스는 메시지를 보내고받을 수있는 소켓과 모든 방법을 가지고있다.

public void Receive() 
{ 
    try 
    { 
     StateObject state = new StateObject(); 
     state.workSocket = socketClient; 
     socketClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state); 
    } 
    catch (Exception e) 
    { 
     throw e; 
    } 
} 

private void ReceiveCallback(IAsyncResult ar) 
     { 
      try 
      { 
       StateObject state = (StateObject)ar.AsyncState; 
       Socket client = state.workSocket; 

       // Read data from the remote device. 
       int iReadBytes = client.EndReceive(ar); 

       if (iReadBytes > state.GetBufferSize()) 
       { 
        byte[] bytesReceived = new byte[iReadBytes]; 
        Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes); 
        state.responseList.Enqueue(bytesReceived); 
        client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, 
         new AsyncCallback(ReceiveCallback), state); 
       } 
       else 
       { 
        byte[] bytesReceived = new byte[iReadBytes]; 
        Buffer.BlockCopy(state.buffer, 0, bytesReceived, 0, iReadBytes); 
        state.responseList.Enqueue(bytesReceived); 
        BuildReceivedMessage(state); 
        receiveDone.Set(); 
       } 
      } 
      catch (Exception e) 
      { 
       throw e; 
      } 
     } 

public class StateObject 
{ 
    public Socket workSocket = null; 
    public const int BufferSize = 20480; 
    public byte[] buffer = new byte[BufferSize]; 

    public Queue<byte[]> responseList = new Queue<byte[]>(); 

    public int GetBufferSize() 
    { 
     return BufferSize; 
    } 
} 

내가 뭘 잘못하고 있니?

답변

1

디자인은 동기식 및 비동기식 프로그래밍의 하이브리드입니다. 적절히 설계된 비동기 클래스는 스레드를 전혀 사용할 필요가 없지만 .NET에서 스레드를 관리하게합니다.

나는이 예제에서 오직 throw e;만이 정말로 희망한다. 이후 스택 추적을 파괴하고 (따라서 예외가 발생한 곳을 숨기고). A는 방법은 다음과 같을 수 있습니다받을 당신은 나의 기사 Don't catch that exception를 읽을 수 있습니다 내 다른 기사는

exceptions 태그 :

void OnReceive(IAsyncResult ar) 
{ 
    AppendInternalReadBuffer(); 
    CheckInternalReadBufferForMessageAndProcessIt(); 
    ReadAgain(); 
} 
클라이언트 당 한 번에 하나 이상의 메시지를 proccessing에서 서버를 차단합니다

. 사물을 복잡하게 만들고 싶지 않다면 CheckInternalReadBufferForMessageAndProcessItThreadPool을 사용할 수 있습니다.

+0

감사합니다. 나는 동기식/비동기식 접근 방식을 결합하여 완전히 어지럽 혔다. – Francesco

2

아무 것도 할 일이없는 스레드에서 비동기 I/O를 사용하면 실제로 어떤 점도 없습니다. 나는이 디자인 결정을 재고 할 것이다.