У меня есть несколько классов, которые «связаны» через различные события. В основном a 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();
}
Я хотел бы избежать делать ничего, что могло бы помешать или замедлить принятие новых клиентов, так что я пытался поднять событие с задачей. Причина этого заключается в том, что пользователь может переопределить метод OnClientConnected
в Server
таким образом, что он работает долго и может повлиять на производительность сервера.
Вот пересмотренный метод:
//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();
}
Когда программа запускается с новым методом, нет никаких исключений на аварии, но сервер не может получить или отправить клиенту.
Вот OnClientConnected
метод Server
:
/// <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}");
}
Просто возвращаясь назад к старому, синхронного метода работает просто отлично.
Что давало мне покоя, что SocketAsyncEventArgs
, который передается через событие кажется правильным, независимо от использования Task
или нет, и что это единственная точка сбоя я могу думать.
SocketAsyncEventArgs
представляется совершенно неправильным при использовании версии метода Task
.
Я подозреваю, что это мое понимание стека, выделенного для нового потока, вызывающего мое замешательство. Может ли кто-нибудь увидеть дыру в моей логике? Благодаря!
PS
Я знаю, что моя текущая реализация в ClientSessions
списка НЕ поточно, но в моем тестировании, я только когда-либо соединяться с одним клиентом одновременно. I будет в конечном итоге исправить это.
PPS Вот StartAccept
метод в случае полезно:
//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' делает asides из 'SocketAsyncEventArgs', но даже копируется в новый стек' Task' (я думаю). Я добавлю «StartAccept» на вопрос, дайте мне знать. –
@dlatikay OH SNAP! Я вижу это сейчас ... 'm_SocketEventArgs.AcceptSocket = null;' ... Вот и все, не так ли? –