2010-11-20 2 views
1

저는 .NET C#에서 TCP 서버를 개발 중입니다. 비동기 I/O (I/O 완료)를 사용하여 많은 수의 클라이언트를 동시에 처리합니다. 지금은 목록에 모든 TCP 연결이 있습니다.이 연결은 특정 연결의 상태 시스템에서 지속적으로 변경을 검색합니다. 지정된 연결에 대한 상태 시스템은 I/O 완료가 특정 플래그를 설정하면 업데이트됩니다.C# .NET Server 다중 연결 폴링 - 더 좋은 방법이 있습니까?

이 작업을 수행하는 더 좋은 방법이 있다고 확신합니다. 현재 업데이트는 업데이트를 기다리는 것을 차단하지 않고 조절을 사용하지 않고 폴링하므로 프로세서 집약적입니다. 내 서버가 사이클을 낭비하고 있는지 신경 쓰지 않지만 가난한 디자인이라고 생각합니다. I/O 완료 신호가 처리해야 할 부분이있을 때만 특정 연결을 처리하는 방법을 찾고, 그렇지 않을 경우 대기 (즉, 휴면)합니다. 아무도 좋은 방법을 제안 할 수 있습니까?

일부 스레드 동기화 작업은 루핑중인 주 스레드에서 I/O 완료가 완료 될 때까지 기다릴 수 있다고 생각했습니다. 그러나 I/O 완료는 호출 스레드 (데이터를 즉시 사용할 수있는 경우 등)를 사용하여 실행되는 경우가 있으므로이 솔루션에서 문제를 일으킬 수 있습니다.

당신이 제안 할 수있는 것은 무엇이든 주시면 감사하겠습니다!

//Do communications on each client we currently have connected. 
//This loops runs backwards so we can delete elements on the fly 
//without have to iterate through more than once. 
lock (rgClient) 
{ 
    for (i = rgClient.Count - 1; i >= 0; i--) 
    { 
     if (!rgClient[i].DoComm()) 
     { 
      rgClient[i].DoClose(); 
      rgClient.RemoveAt(i); 
     } 
    } 
} 

DoComm() 연결에 대한 상태 머신의 업데이트를 수행하고, 수반 : 여기

메인 쓰레드에 의해 실행된다 (간략화 된) 루프 (rgClient 클라이언트의리스트 임) 현재 상태의 활동을 실행 한 다음 필요한 경우 새 상태로 전환합니다.

class StateAck : State 
{ 
    public StateAck(TextBox txtOutputExt, Form fmOwner) 
     : base(txtOutputExt, fmOwner) 
    { 
     fWriting = false; 
    } 

    public override bool DoExecute(out Type tpNextState) 
    { 
     PktAck pkt; 

     if (!base.DoExecute(out tpNextState)) 
     { 
      return false; 
     } 

     //Start a write if we haven't yet 
     if (!fWriting) 
     { 
      pkt = new PktAck(); 
      fWriting = true; 

      return FPutPkt(pkt.rgbSerialize()); 
     } 

     //Is the read finished/has an error occurred? 
     if (fDataErrorWrite) 
     { 
      return false; 
     } 

     //Process the data 
     if (fDataWritten) 
     { 
      tpNextState = typeof(StateIdle); 
     } 

     return true; 
    } 

    private bool fWriting; 
} 

실행이 DoExecute 통과()마다 DoComm() 메인 스레드에서 호출 : 다음은 간단한 "ACK"패킷을 전송하는 상태 클래스입니다. 99 %의 시간, 실제로는 아무 것도 발생하지 않습니다. FPutPkt()를 호출하여 시작된 쓰기가 완료되면 플래그가이를 알리고 다음 상태가 "유휴"로 설정됩니다. 내가하고 싶은 일은 메인 스레드가 네트워크 활동을 끝내고 DoExecute()를 통해 상수 및 중복 전달을 피하기 위해 업데이트가 필요한 클라이언트 만 검사하는 것입니다.

+2

나는 코드를 보여줄 것을 제안합니다. 이렇게하면 토론의 기반이됩니다. –

+0

그리고 왜 I/O 완료 루틴이이를 처리 할 수 ​​없습니까? I/O 완료를 사용하는 것이 전부 아닌가? –

+0

이 기사를 확인할 수 있습니다. http://www.codeproject.com/KB/IP/dotnettcp.aspx – Iraklis

답변

0

나는 꽤 잘 작동하는 해결책을 발견했습니다. 루프를 통과 할 때마다 WaitOne()에 자동 재설정 된 EventWaitHandler (System.Threading)를 사용하십시오. 그런 다음 콜백 또는 보조 스레드는 EWH.Set()을 호출하여 EventWaitHandler에 신호를 보낼 수 있습니다. 그러면 루프가 다른 패스를 만들 수 있습니다. 프로그램 흐름을 크게 수정하지 않고 폴링 루프의 CPU 사용을 제거하는 가장 좋은 방법입니다. 누군가가 도움이되기를 바랍니다.