【问题标题】:.NET CF - Socket.BeginReceive - Does this ever throw a SocketException?.NET CF - Socket.BeginReceive - 这会抛出 SocketException 吗?
【发布时间】:2012-02-09 21:35:21
【问题描述】:

我一直在研究如何根据http://msdn.microsoft.com/en-us/library/dxkwh6zw(v=vs.90).aspx 在 .NET CF 套接字上调用 BeginReceive 引发 SocketException?

我查看了反射器,但看不到这怎么可能?我认为只有在线程池线程中实际执行工作时才可能出现 SocketException。

我的猜测是任何 SocketException 都是通过 EndReceive() 的通道。

我有一个调用自身的回调方法(即 BeginReceive(.., .., callback),其中包含一个 EndReceive。我想确保在正确的位置添加一个 Try-catch。

有什么想法吗?

【问题讨论】:

  • 即使您找不到任何会发生的原因,我也会尝试/抓住它。添加保护不需要任何成本,如果(我知道,如果)CF 得到更新,或者如果您在 anotehr 平台上重用代码更有可能,您仍然受到保护。
  • @ctacke 你是对的。事实上,我在整个方法中都使用了 try-catch……只是为了涵盖……大多数可能性。

标签: .net sockets compact-framework


【解决方案1】:

我查看了.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 所述

这是开始接收

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;
}

线程调用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

【讨论】:

  • 不确定 .NET Compact Framework 套接字是否相同?
  • @msuhash 我不能肯定地说,但深入挖掘 .NET 代码,错误来自对 Win32 库的调用。这是 Windows 本机套接字错误代码,并且 99.9% 肯定会在各个平台上相同。将发布更新的位置代码。
【解决方案2】:

@布拉德

这是我在 .NET CF 中看到的。我同意你对整个框架的分析。

以下是针对 CF 的。

(1)

public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state) { this.throwIfDisposed(); 如果(缓冲区 == 空) { 抛出新的 ArgumentNullException("buffer"); } 如果(偏移量&lt 0) { 抛出新的 ArgumentOutOfRangeException("offset"); } 如果(大小 &lt 0) { 抛出新的 ArgumentOutOfRangeException("size"); } if (buffer.Length &lt (offset + size)) { 抛出新的 ArgumentOutOfRangeException(null, SR.GetString(0x44, new object[0])); } ReceiveAsyncRequest req = new ReceiveAsyncRequest(this, buffer, offset, size, socketFlags, callback, state); this.addReadRequest(req); 返回请求; }

(2)

私人无效 addReadRequest(AsyncRequest req) { 锁(这个) { 如果(this.m_readHead == null) { if (!startWorker(req)) { req.InvokeCallback(false, new OutOfMemoryException(SR.GetString(0x45, new object[0]))); } 别的 { this.m_readHead = 请求; } } 别的 { AsyncRequest readHead = this.m_readHead; 而(readHead.m_next!= null) { 读头 = 读头.m_next; } readHead.m_next = 请求; } } }

“startWorker”只是在线程池线程中对项目进行排队。

(3)

私有静态 bool startWorker(AsyncRequest req) { WorkerThread 线程 = new WorkerThread(req); if (!ThreadPool.QueueUserWorkItem(new WaitCallback(thread.doWorkI))) { 返回假; } 返回真; }

可能是我的眼睛在玩游戏,但我看不到 SocketException。

谢谢,

【讨论】:

  • 看看我的答案,我对其进行了编辑以包含 CF。它确实会引发异常,您只需遵循代码即可。我花了一段时间才意识到这一点。
  • 我同意,但是这个 SocketException 不是发生在线程池中吗?因此,消费者在调用 EndReceive 时会收到此异常?
  • 在底部添加了更多关于此的内容。
  • @Brad - 我认为你是对的。 (见这个 - social.msdn.microsoft.com/Forums/en-GB/ncl/thread/…)。感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 2014-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-23
  • 2011-12-27
  • 2011-10-27
相关资源
最近更新 更多