我看了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,
out bytesTransferred,
ref socketFlags,
asyncResult.OverlappedHandle,
IntPtr.Zero); if (errorCode!=SocketError.Success) {
errorCode = (SocketError)Marshal.GetLastWin32Error();
GlobalLog.Assert(errorCode != SocketError.Success, "Socket#{0}::DoBeginReceive()|GetLastWin32Error() returned zero.", ValidationHelper.HashString(this));
}
GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceive() UnsafeNclNativeMethods.OSSOCK.WSARecv returns:" + errorCode.ToString() + " bytesTransferred:" + bytesTransferred.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
}
finally
{
errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
}
//
// if the asynchronous native call fails synchronously
// we'll throw a SocketException
//
if (errorCode != SocketError.Success)
{
//
// update our internal state after this socket error and throw
asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
UpdateStatusAfterSocketError(errorCode);
if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceive", new SocketException(errorCode));
asyncResult.InvokeCallback(new SocketException(errorCode));
}
#if DEBUG
else
{
m_LastReceiveHandle = lastHandle;
m_LastReceiveThread = Thread.CurrentThread.ManagedThreadId;
m_LastReceiveTick = Environment.TickCount;
}
#endif return errorCode;
}
{
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,
out bytesTransferred,
ref socketFlags,
asyncResult.OverlappedHandle,
IntPtr.Zero); if (errorCode!=SocketError.Success) {
errorCode = (SocketError)Marshal.GetLastWin32Error();
GlobalLog.Assert(errorCode != SocketError.Success, "Socket#{0}::DoBeginReceive()|GetLastWin32Error() returned zero.", ValidationHelper.HashString(this));
}
GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceive() UnsafeNclNativeMethods.OSSOCK.WSARecv returns:" + errorCode.ToString() + " bytesTransferred:" + bytesTransferred.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
}
finally
{
errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
}
//
// if the asynchronous native call fails synchronously
// we'll throw a SocketException
//
if (errorCode != SocketError.Success)
{
//
// update our internal state after this socket error and throw
asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
UpdateStatusAfterSocketError(errorCode);
if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceive", new SocketException(errorCode));
asyncResult.InvokeCallback(new SocketException(errorCode));
}
#if DEBUG
else
{
m_LastReceiveHandle = lastHandle;
m_LastReceiveThread = Thread.CurrentThread.ManagedThreadId;
m_LastReceiveTick = Environment.TickCount;
}
#endif return errorCode;
}
{
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,
out bytesTransferred,
ref socketFlags,
asyncResult.OverlappedHandle,
IntPtr.Zero); if (errorCode!=SocketError.Success) {
errorCode = (SocketError)Marshal.GetLastWin32Error();
GlobalLog.Assert(errorCode != SocketError.Success, "Socket#{0}::DoBeginReceive()|GetLastWin32Error() returned zero.", ValidationHelper.HashString(this));
}
GlobalLog.Print("Socket#" + ValidationHelper.HashString(this) + "::BeginReceive() UnsafeNclNativeMethods.OSSOCK.WSARecv returns:" + errorCode.ToString() + " bytesTransferred:" + bytesTransferred.ToString() + " returning AsyncResult:" + ValidationHelper.HashString(asyncResult));
}
finally
{
errorCode = asyncResult.CheckAsyncCallOverlappedResult(errorCode);
} //
// if the asynchronous native call fails synchronously
// we'll throw a SocketException
//
if (errorCode != SocketError.Success)
{
//
// update our internal state after this socket error and throw
asyncResult.ExtractCache(ref Caches.ReceiveOverlappedCache);
UpdateStatusAfterSocketError(errorCode);
if(s_LoggingEnabled)Logging.Exception(Logging.Sockets, this, "BeginReceive", new SocketException(errorCode));
asyncResult.InvokeCallback(new SocketException(errorCode));
}
#if DEBUG
else
{
m_LastReceiveHandle = lastHandle;
m_LastReceiveThread = Thread.CurrentThread.ManagedThreadId;
m_LastReceiveTick = Environment.TickCount;
}
#endif return errorCode;
}