我一直在研究如何在.NET CF套接字上调用BeginReceive可以按http://msdn.microsoft.com/en-us/library/dxkwh6zw(v=vs.90).aspx抛出SocketException?
我查看了反射器,但我看不出这是怎么回事?我认为SocketException只有在实际在线程池线程中完成工作时才有可能。
我的猜测是任何SocketException都是通过EndReceive()的通道。
我有一个调用自身的回调方法(即BeginReceive(..,..,回调),它包含一个EndReceive。我想确保在正确的位置添加一个Try-catch。
有什么想法吗?
答案 0 :(得分:2)
我查看了.NET Reference Source,它会抛出异常。
代码:
[HostProtection(ExternalThreading=true)]
public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
{
SocketError errorCode;
IAsyncResult result = BeginReceive(buffer, offset, size, socketFlags, out errorCode, callback, state);
if(errorCode != SocketError.Success && errorCode !=SocketError.IOPending){
throw new SocketException(errorCode);
}
return result;
}
在一个名为DoBeginReceive的方法中从Begin的重载调用的方法中,此方法调用此代码。错误代码使用out关键字传递,因此它正是传回的内容。
errorCode = UnsafeNclNativeMethods.OSSOCK.WSARecv(
m_Handle,
ref asyncResult.m_SingleBuffer,
1,
out bytesTransferred,
ref socketFlags,
asyncResult.OverlappedHandle,
IntPtr.Zero);
编辑:对于.NET CF:
由OP指出
这是Begin Receive
public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
{
this.throwIfDisposed();
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if (offset < 0)
{
throw new ArgumentOutOfRangeException("offset");
}
if (size < 0)
{
throw new ArgumentOutOfRangeException("size");
}
if (buffer.Length < (offset + size))
{
throw new ArgumentOutOfRangeException("", SR.GetString(0x41, new object[0]));
}
ReceiveAsyncRequest req = new ReceiveAsyncRequest(this, buffer, offset, size, socketFlags, callback, state);
this.addReadRequest(req);
return req;
}
addReadRequest执行此操作:
private void addReadRequest(AsyncRequest req)
{
lock (this)
{
if (this.m_readHead == null)
{
if (!startWorker(req))
{
req.InvokeCallback(false, new OutOfMemoryException(SR.GetString(0x42, new object[0])));
}
else
{
this.m_readHead = req;
}
}
else
{
AsyncRequest readHead = this.m_readHead;
while (readHead.m_next != null)
{
readHead = readHead.m_next;
}
readHead.m_next = req;
}
}
}
startWorker执行此操作:
private static bool startWorker(AsyncRequest req)
{
WorkerThread thread = new WorkerThread(req);
if (!ThreadPool.QueueUserWorkItem(new WaitCallback(thread.doWorkI)))
{
return false;
}
return true;
}
Thread调用ReceiveAsyncRequest的doWork调用ReceiveAsyncRequest的doRequest,调用handleRequest,handleRequest又调用ReceiveAsyncRequest上的doRequest。
ReceiveAsyncRequest方法的doRequest如下所示:
protected override object doRequest()
{
return base.m_socket.ReceiveNoCheck(this.m_readBuffer, this.m_index, this.m_size, this.m_flags);
}
在ReceiveFromNoCheck中,它抛出异常:
internal int ReceiveFromNoCheck(byte[] buffer, int index, int request, SocketFlags flags)
{
this.throwIfDisposed();
int rc = 0;
int num2 = OSSOCK.recv(this.handle, buffer, index, request, (int) flags, ref rc);
if(num2 < 0)
{
throw new SocketException(rc);
}
return num2;
}
如果AsyncResults运行sychronously,它将抛出异常。但是,如果它是ThreadPool的一部分,则抛出异常并kill the application。
答案 1 :(得分:0)
@Brad
这就是我在.NET CF中看到的。我同意你对完整框架的分析。
以下是CF。
(1)
public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state) { this.throwIfDisposed(); if (buffer == null) { throw new ArgumentNullException("buffer"); } if (offset < 0) { throw new ArgumentOutOfRangeException("offset"); } if (size < 0) { throw new ArgumentOutOfRangeException("size"); } if (buffer.Length < (offset + size)) { throw new ArgumentOutOfRangeException(null, SR.GetString(0x44, new object[0])); } ReceiveAsyncRequest req = new ReceiveAsyncRequest(this, buffer, offset, size, socketFlags, callback, state); this.addReadRequest(req); return req; }
(2)
private void addReadRequest(AsyncRequest req) { lock (this) { if (this.m_readHead == null) { if (!startWorker(req)) { req.InvokeCallback(false, new OutOfMemoryException(SR.GetString(0x45, new object[0]))); } else { this.m_readHead = req; } } else { AsyncRequest readHead = this.m_readHead; while (readHead.m_next != null) { readHead = readHead.m_next; } readHead.m_next = req; } } }
“startWorker”只是在线程池线程中对项目进行排队。
(3)
private static bool startWorker(AsyncRequest req) { WorkerThread thread = new WorkerThread(req); if (!ThreadPool.QueueUserWorkItem(new WaitCallback(thread.doWorkI))) { return false; } return true; }
可能是我的眼睛正在玩游戏,但我无法发现SocketException。
谢谢,