다양한 이벤트를 통해 "링크 된"몇 개의 클래스가 있습니다. 기본적으로 TCPListener
, ClientSession
및 Server
입니다.작업에서 이벤트를 발생 시키면 구독자 메서드가 실패합니다.
TCPListener
은 Server
까지 새 연결을 거품화한 다음 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
여부를 사용하여 올바른 것 같다 그리고 내가 생각할 수있는 실패의 유일한 점 때문이다.
SocketAsyncEventArgs
은 Task
버전의 방법을 사용할 때 완전히 잘못된 것처럼 보입니다.
내 혼란을 일으키는 새로운 스레드에 할당 된 스택을 이해하고 있다고 생각됩니다. 누구든지 내 논리에 구멍을 볼 수 있습니까? 감사!
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);
}
}
StartAccept로 경주 만하는 것이 아닙니다. – dlatikay
@dlatikay 그렇게 생각하지 마십시오.'StartAccept'는'ClientConnected'가'SocketAsyncEventArgs'를 무시하고 새로운'Task'의 스택으로 복사되는 것 (나는 생각합니다)에 영향을주지 않습니다. 질문에 'StartAccept'을 추가하겠습니다. 알려주세요. –
@dlatikay OH SNAP! 이제 알 겠어 ... 'm_SocketEventArgs.AcceptSocket = null;'... 그게 맞습니까? –