Я смотрю на исходный код для сервера с помощью SocketAsyncEventArgs, и я пытаюсь выяснить, как это не будет вызывать переполнение стека:Как это не вызывает переполнение стека?
Так что этот код называется, чтобы сокет, чтобы принять входящее соединение (прокрутите вниз до нижней части, чтобы увидеть, что я имею в виду):
/// <summary>
/// Begins an operation to accept a connection request from the client.
/// </summary>
/// <param name="acceptEventArg">The context object to use when issuing
/// the accept operation on the server's listening socket.</param>
private void StartAccept(SocketAsyncEventArgs acceptEventArg)
{
if (acceptEventArg == null)
{
acceptEventArg = new SocketAsyncEventArgs();
acceptEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(OnAcceptCompleted);
}
else
{
// Socket must be cleared since the context object is being reused.
acceptEventArg.AcceptSocket = null;
}
this.semaphoreAcceptedClients.WaitOne();
Boolean willRaiseEvent = this.listenSocket.AcceptAsync(acceptEventArg);
if (!willRaiseEvent)
{
this.ProcessAccept(acceptEventArg);
}
}
Затем этот код вызывается когда соединение фактически принято (см, последнюю строку):
/// <summary>
/// Process the accept for the socket listener.
/// </summary>
/// <param name="e">SocketAsyncEventArg associated with the completed accept operation.</param>
private void ProcessAccept(SocketAsyncEventArgs e)
{
if (e.BytesTransferred > 0)
{
Interlocked.Increment(ref this.numConnectedSockets);
Console.WriteLine("Client connection accepted. There are {0} clients connected to the server",
this.numConnectedSockets);
}
// Get the socket for the accepted client connection and put it into the
// ReadEventArg object user token.
SocketAsyncEventArgs readEventArgs = this.readWritePool.Pop();
readEventArgs.UserToken = e.AcceptSocket;
// As soon as the client is connected, post a receive to the connection.
Boolean willRaiseEvent = e.AcceptSocket.ReceiveAsync(readEventArgs);
if (!willRaiseEvent)
{
this.ProcessReceive(readEventArgs);
}
// Accept the next connection request.
this.StartAccept(e); // <==== tail end recursive?
}
Посмотрите на последний линия. Он снова вызывает верхнюю функцию. Как это не переполняет стек путем ping-ponging назад и вперед между этими двумя функциями? Кажется, это рекурсия конца хвоста, но это не Haskell, поэтому я не вижу, как это будет работать.
Это было мое понимание, что они не были выпущены в потоки, но только что выполнялись по одному за процессор.