2009-12-08 2 views
0

C#에서 TcpClient 클래스를 사용하고 있습니다.C# : 처리기가 TCP 처리기 스레드에서 신호를 종료합니까?

새로운 tcp 연결 요청이있을 때마다 일반적으로이를 처리 할 새 스레드를 만드는 것이 좋습니다. 그리고 메인 쓰레드가 언제든지이 핸들러 쓰레드를 종료 할 수 있어야한다.

다음과 같이 이러한 핸들러 스레드 각각에 대한 내 솔루션은 다음과 같습니다

1 Check NetworkStream's DataAvailable method 
    1.1 If new data available then read and process new data 
    1.2 If end of stream then self terminate 
2 Check for terminate signal from main thread 
    2.1 If terminate signal activated then self terminate 
3 Goto 1. 

이 폴링 방식의 문제는 이러한 핸들러 스레드의 모든 중요한 프로세서 자원을 복용하고 특히 경우 그래서를이 될 것입니다 거대한 수의 스레드. 이로 인해 매우 비효율적입니다.

더 좋은 방법이 있나요?

+0

왜 커뮤니티 위키입니까? –

+0

실수로 해당 옵션을 클릭했는데 다시 변경할 수 없습니다 !!! – Lopper

답변

2

각 요청마다 새 스레드를 만들지 않고 ".NET 방식"을 수행하는 방법을 보려면 Asynchronous Server Socket Example을 참조하십시오.

+0

그러나 비동기 I/O 방식은 종료를 제공하는 방법을 제공하지 않습니다. 어떤 이유로 든 사용자가 응용 프로그램을 종료하려고하지만 들어오는 데이터가 아직 없지만 지연없이 응용 프로그램을 즉시 종료해야하기 때문에 각 콜백 함수를 아직 호출하지 않은 비동기 호출이 있습니다. – Lopper

+0

음, 비동기 IO는 스레드 (풀)를 생성하는 대신 내부적으로 사용합니다. 그래서 내 의견으로는 오래 지속되는 연결 수가 많으면 ThreadPool을 사용하는 다른 응용 프로그램이 스레드 풀을 사용하는 대신 각 스레드에 전용 스레드를 갖는 것이 더 좋습니다. – A9S6

+1

@Lopper : 종료하는 한 가지 방법은 단순히 다음 작업을 시작하지 않는 것입니다. 독서 했니? 다른 BeginRead를하지 마십시오. 나는 또한'TcpClient' 인스턴스를 닫으면 취소 할 것으로 의심된다. –

0

비슷한 종류의 Windows 서비스에서 작업 한 것을 기억합니다. 그것은 약 1000 개의 TCP 연결을 가지고 NTRIP Caster로 데이터를 라우팅 할 수있는 NTRIP 서버였습니다.

이 응용 프로그램을위한 전용 서버가있는 경우 각 스레드 (파일 IO, 데이터베이스 등 - 추가/내 경우에는 데이터베이스 처리가 있었지만 더 많은 코드를 추가하지 않으면 문제가되지 않습니다 각 연결마다). 조심하는

것들 :

  1. 대역폭 스레드가 600 정도까지 간다. 는 TCP 버퍼 창은 어떤 이유로 질식하거나 사용 가능한 대역폭이 미달 될 때 당신은 단선을보고 시작합니다
  2. 있는 당신이 단선에게

을 일으킬 수있는 몇 가지 제한 사항이있을 수 있습니다이 응용 프로그램을 실행하는 운영 체제 위의 경우 귀하의 경우에는 적용되지 않을 수도 있습니다하지만 난 단지 개발에 직면했기 때문에 여기에 넣어 싶었어.

0

모든 스레드가 "대기 중"(예 : 계속 반복되는 작은 루프)하지 않기를 바랍니다. 차단을 원하거나 비동기 I/O를 사용하려고합니다.

John Saunders가 언급했듯이 비동기 I/O는 수백 개의 연결로 확장 할 수 있기 때문에이를 수행하는 "올바른 방법"입니다. 기본적으로 BeginRead()를 호출하고 콜백 함수를 전달합니다. BeginRead()는 즉시 반환하고 데이터가 도착하면 스레드 풀에서 스레드에서 콜백 함수가 호출됩니다. 콜백 함수는 데이터를 처리하고 BeginRead()를 다시 호출 한 다음 반환하여 스레드를 풀에 다시 릴리스합니다.

그러나 한 번에 몇 개의 연결 만 열어두면 각 연결마다 스레드를 만드는 것이 좋습니다. 루프에서 DataAvailable 속성을 확인하는 대신 Read()를 호출하십시오. 스레드가 데이터를 읽을 수있을 때까지 CPU를 소비하지 않고 블록됩니다. 연결이 끊어 지거나 다른 스레드에서 닫을 경우 Read() 호출은 예외를 throw합니다.이 예외는 독자 스레드를 종료하여 처리 할 수 ​​있습니다.

+0

그러나 비동기 I/O 방식은 종료를 제공하는 방법을 제공하지 않습니다. 어떤 이유로 사용자가 응용 프로그램을 종료하려고하고 아직 들어오는 데이터가 없기 때문에 각 콜백 함수를 호출하지 않은 비동기 호출이 있습니다. – Lopper

1

믿지 않겠습니까? 그렇지 않으면 1000 틱 수면은 실제로 물건을 매끄럽게 유지합니다.

private readonly Queue<Socket> sockets = new Queue<Socket>(); 
private readonly object locker = new object(); 
private readonly TimeSpan sleepTimeSpan = new TimeSpan(1000); 
private volatile Boolean terminate; 

private void HandleRequests() 
{ 
    Socket socket = null; 

    while (!terminate) 
    { 
     lock (locker) 
     { 
      socket = null; 
      if (sockets.Count > 0) 
      { 
       socket = sockets.Dequeue(); 
      } 
     } 

     if (socket != null) 
     { 
      // process 
     } 

     Thread.Sleep(sleepTimeSpan); 
    } 
} 
+0

내가 틀렸다면 정정해라.하지만 위 코드가 단지 하나의 쓰레드가 TCP 연결에서 들어오는 데이터의 읽기/처리를 수행한다는 것을 의미한다. if (socket! = null) 블록 내부에서 데이터를 처리하는 데 상당한 시간이 필요한 경우에는 다른 연결을 처리하기 전에 상당한 지연이 발생할 것으로 생각됩니다. 각 소켓의 처리가 병렬로 진행될 수있는 동시에 폴링 방식을 사용하지 않는 더 좋은 방법이 있습니까? – Lopper

+0

아니요, 아니요, 처리기 스레드를 만들 때 처리기 스레드로 전달하는 메서드입니다. – ChaosPandion