2017-02-06 10 views
0

다양한 이벤트를 통해 "링크 된"몇 개의 클래스가 있습니다. 기본적으로 TCPListener, ClientSessionServer입니다.작업에서 이벤트를 발생 시키면 구독자 메서드가 실패합니다.

TCPListenerServer까지 새 연결을 거품화한 다음 Server은 새 ClientSession을 만듭니다.

TCPListener은 이벤트를 통해 새 소켓을 전달합니다 (ClientConnected).

이벤트를 높이는 방법은 다음과 같습니다

//Processes a new connection and immediately puts the listen socket back in a receiving state 
    private void ProcessAccept(SocketAsyncEventArgs e) 
    { 
     ClientConnected(this, e));    

     StartAccept(); 
    } 

내가 그래서이 작업과 이벤트를 발생하기 위해 노력 방지하거나 새로운 클라이언트의 수용을 늦출 수있는 일을 아무것도하지 않도록하고 싶었다. 그 이유는 사용자가 Server에서 OnClientConnected 메서드를 재정의 할 수 있기 때문에 서버 실행 시간이 오래 걸리고 서버 성능에 영향을 줄 수 있기 때문입니다. 프로그램이 새로운 방법으로 실행

//Processes a new connection and immediately puts the listen socket back in a receiving state 
    private void ProcessAccept(SocketAsyncEventArgs e) 
    { 
     Task.Run(() => ClientConnected(this, e));    

     StartAccept(); 
    } 

, 충돌에 예외가없는, 아직 서버는 수신하거나 클라이언트로 보낼 수 없습니다 : 여기

는 개정 된 방법이다.

/// <summary> 
    /// An event that is fired when a client connects. 
    /// </summary> 
    /// <param name="sender">The Listener that accepted the connection</param> 
    /// <param name="e">The SocketAsyncEventArgs </param> 
    protected virtual void OnClientConnected(object sender, EventArgs e) 
    { 
     ClientSession Session = ClientSessionPool.Pop(); 

     Session.Socket = ((SocketAsyncEventArgs)e).AcceptSocket; 

     string WelcomeMessage = "Connected"; 

     Session.SendAsync(Encoding.Default.GetBytes(WelcomeMessage)); 

     this.ClientSessions.Add(Session); 

     Console.Write($"\rConnected clients:{ClientSessions.Count}"); 
    } 

간단히 예전의 동기 방법에 되 돌리는 것은 잘 작동 : 여기

Server에서 OnClientConnected 방법이다. 나를 괴롭히는 무엇

이벤트를 통해 전달되는 SocketAsyncEventArgs에 관계없이 Task 여부를 사용하여 올바른 것 같다 그리고 내가 생각할 수있는 실패의 유일한 점 때문이다.

SocketAsyncEventArgsTask 버전의 방법을 사용할 때 완전히 잘못된 것처럼 보입니다.

내 혼란을 일으키는 새로운 스레드에 할당 된 스택을 이해하고 있다고 생각됩니다. 누구든지 내 논리에 구멍을 볼 수 있습니까? 감사!

PS

나는 ClientSessions 목록의 나의 현재 구현은 스레드로부터 안전하지 않습니다 것을 알고,하지만 내 테스트에서, 나는 오직 한 번에 하나의 클라이언트와 연결하고있다. 내가 최종 수정됩니다. 솔루션에

//Puts the accepting TCP socket back into an accepting state 
    public void StartAccept() 
    { 
     // socket must be cleared since the context object is being reused 
     m_SocketEventArgs.AcceptSocket = null; 

     bool willRaiseEvent = m_Socket.AcceptAsync(m_SocketEventArgs); 
     if (!willRaiseEvent) 
     { 
      ProcessAccept(m_SocketEventArgs); 
     } 
    } 
+0

StartAccept로 경주 만하는 것이 아닙니다. – dlatikay

+0

@dlatikay 그렇게 생각하지 마십시오.'StartAccept'는'ClientConnected'가'SocketAsyncEventArgs'를 무시하고 새로운'Task'의 스택으로 복사되는 것 (나는 생각합니다)에 영향을주지 않습니다. 질문에 'StartAccept'을 추가하겠습니다. 알려주세요. –

+1

@dlatikay OH SNAP! 이제 알 겠어 ... 'm_SocketEventArgs.AcceptSocket = null;'... 그게 맞습니까? –

답변

2

는 UI 스레드에 이벤트를 발생하지만, 비동기 이벤트 처리를 실행하는 것입니다 :

여기에 PPS 는 유용 경우에 StartAccept 방법이다.

private async void OnClientConnected(object sender, EventArgs e) 
{ 
    await Task.Run(() => HandleClientConnected(object, e)); 
} 

protected abstract Task HandleClientConnected(object sender, EventArgs e); 
+0

콘솔 프로그램에 여전히 "UI"스레드가있는 것으로 간주되는지 확실하지 않습니다. 나는 이것이 무엇을 성취 할 수 있을지 이해하지 못한다 ...이 작업은 본질적으로이 방법을 동기식 및 비 - 병렬 식으로 완성 할 때까지 차단되지 않을까? –

+0

@ Connel.O'Donnell 내가 본 것 같아. 그것은 단지 과제의 창조 *를 기다리고 있습니까? 그리고 실행은 아닙니다. –

+0

정확합니다. 또는 처리기를 기다리지 않고 화재 및 잊지 명령으로 처리 할 수도 있습니다. –