日期:2014-05-18  浏览次数:20911 次

谁能告诉我C#中的Socket的BeginReceive内部是如何异步的?
我看了Socket源代码,但是不是很了解它的原理,它是就调用了WSARecv这个函数然后我不知道它是什么时候进行回调的,它是用WSAEventSelect?

public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback callback, object state) 
  {
   
  if (CleanedUp) {
  throw new ObjectDisposedException(this.GetType().FullName); 
  } 

  // 
  // parameter validation
  //
  if (buffer==null) {
  throw new ArgumentNullException("buffer"); 
  }
  if (offset<0 || offset>buffer.Length) { 
  throw new ArgumentOutOfRangeException("offset"); 
  }
  if (size<0 || size>buffer.Length-offset) { 
  throw new ArgumentOutOfRangeException("size");
  }

  // We need to flow the context here. But we don't need to lock the context - we don't use it until the callback. 
  OverlappedAsyncResult asyncResult = new OverlappedAsyncResult(this, state, callback);
  asyncResult.StartPostingAsyncOp(false); 
 
  // Run the receive with this asyncResult.
  errorCode = DoBeginReceive(buffer, offset, size, socketFlags, asyncResult); 

  if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
  asyncResult = null;
  } 
  else
  { 
  // We're not throwing, so finish the async op posting code so we can return to the user. 
  // If the operation already finished, the callback will be called from here.
  asyncResult.FinishPostingAsyncOp(ref Caches.ReceiveClosureCache); 
  }

  if(s_LoggingEnabled)Logging.Exit(Logging.Sockets, this, "BeginReceive", asyncResult);
  return asyncResult; 
  }

private SocketError DoBeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, OverlappedAsyncResult asyncResult) 
  { 
  GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceive() size:" + size.ToString());
 
#if DEBUG
  IntPtr lastHandle = m_Handle.DangerousGetHandle();
#endif
  // Guarantee to call CheckAsyncCallOverlappedResult if we call SetUnamangedStructures with a cache in order to 
  // avoid a Socket leak in case of error.
  SocketError errorCode = SocketError.SocketError; 
  try 
  {
  // Set up asyncResult for overlapped WSARecv. 
  // This call will use completion ports on WinNT and Overlapped IO on Win9x.
  asyncResult.SetUnmanagedStructures(buffer, offset, size, null, false /* don't pin null RemoteEP*/, ref Caches.ReceiveOverlappedCache);

  // This can throw ObjectDisposedException. 
  int bytesTransferred;
  errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv( 
  m_Handle, 
  ref asyncResult.m_SingleBuffer,
  1,