C# 这如何不会导致堆栈溢出?

C# 这如何不会导致堆栈溢出?,c#,C#,我正在查看使用SocketAsyncEventArgs的服务器的源代码,并试图找出这如何不会导致堆栈溢出: 因此,调用此代码是为了允许套接字接受传入连接(向下滚动到底部以了解我的意思): // ///开始接受来自客户端的连接请求的操作。 /// ///发出时要使用的上下文对象 ///服务器侦听套接字上的接受操作。 私有void StartAccept(SocketAsyncEventArgs acceptEventArg) { if(acceptEventArg==null) { accept

我正在查看使用SocketAsyncEventArgs的服务器的源代码,并试图找出这如何不会导致堆栈溢出:

因此,调用此代码是为了允许套接字接受传入连接(向下滚动到底部以了解我的意思):

//
///开始接受来自客户端的连接请求的操作。
/// 
///发出时要使用的上下文对象
///服务器侦听套接字上的接受操作。
私有void StartAccept(SocketAsyncEventArgs acceptEventArg)
{
if(acceptEventArg==null)
{
acceptEventArg=新的SocketAsyncEventArgs();
acceptEventArg.Completed+=新的事件处理程序(OnAcceptCompleted);
}
其他的
{
//由于正在重用上下文对象,因此必须清除套接字。
acceptEventArg.AcceptSocket=null;
}
this.semaphoreAcceptedClients.WaitOne();
布尔值willRaiseEvent=this.listenSocket.acceptsync(acceptEventArg);
如果(!willRaiseEvent)
{
此.ProcessAccept(acceptEventArg);
}
}
一旦连接被实际接受,就会调用此代码(请参见最后一行):

//
///处理套接字侦听器的接受。
/// 
///与已完成的接受操作关联的SocketAsyncEventArg。
私有void ProcessAccept(SocketAsyncEventArgs e)
{
如果(例如,ByTestTransferred>0)
{
联锁增量(参考此numConnectedSockets);
Console.WriteLine(“已接受客户端连接。有{0}个客户端连接到服务器”,
这是一个新的接口(numConnectedSockets);
}
//获取接受的客户端连接的套接字并将其放入
//ReadEventArg对象用户令牌。
SocketAsyncEventArgs readEventArgs=this.readWritePool.Pop();
readEventArgs.UserToken=e.AcceptSocket;
//客户端连接后,立即向连接发送接收。
布尔值willRaiseEvent=e.AcceptSocket.ReceiveAsync(readEventArgs);
如果(!willRaiseEvent)
{
this.ProcessReceive(readEventArgs);
}
//接受下一个连接请求。
这个.startacept(e);//看看代码:

if (!willRaiseEvent)
{
    this.ProcessAccept(acceptEventArg);
}

虽然我还不了解整个机制,但是willRaiseEvent==true显然会结束递归,所以我猜这不是无止境的递归。

这一切都取决于
WillCauseeEvent
标志,当设置为true时会中断递归。
如果没有挂起的连接,则该标志可能设置为true。

很难从上下文中确定,但看起来第一个标志仅在以下情况下直接调用第二个标志

Boolean willRaiseEvent = this.listenSocket.AcceptAsync(acceptEventArg);    
if (!willRaiseEvent)    
{
因此,我猜大多数情况下,它会在完成时引发一个事件(来自不同的回调线程)

(另请参见

这似乎是一种类似的事情。)

ProcessAccept()
总是调用
StartAccept()
,但事实并非如此

startacept()
中,只有当
willRaiseEvent
设置为true时,才会调用
ProcessAccept()
。这就是从无限递归中退出

如果您怀疑无限递归(在单个递归函数或乒乓函数中,正如您雄辩地说的那样:-),您总是寻找可能的退出点。

如果AsyncAccept(或任何AsyncXXX操作)无法立即满足,则将返回true,指示操作将异步完成。发生这种情况时,回调事件最终将在线程池线程上触发。即使它封送回UI线程(因为它是在那里启动的),它也将通过post执行

AsyncAccept很可能返回true,因为除非存在真正挂起的套接字连接(请参阅中的backlog),否则您将等待客户端连接

因此,StartAccept()将在不调用ProcessAccept的情况下直接退出,而ProcessAccept在触发时(如果触发)可能位于不同的线程上

if (!willRaiseEvent)
{
    this.ProcessAccept(acceptEventArg);
}
Boolean willRaiseEvent = this.listenSocket.AcceptAsync(acceptEventArg);    
if (!willRaiseEvent)    
{