【问题标题】:ObjectDisposedException throw when EndReceive is call (Asynchronous Client Socket)调用 EndReceive 时抛出 ObjectDisposedException(异步客户端套接字)
【发布时间】:2018-07-09 04:52:46
【问题描述】:

我正在开发一个 C# 程序,我想在其中与 wifi 模块 (RN 171) 交谈。

在我的 Program.cs 中,当我收到 RabbitMQ 消息时,我会直接调用我的 Start 方法。

我从this 示例(异步客户端套接字示例)开始。

错误指示发生在以下行:

int bytesRead = client.EndReceive(ar);

但它真的出现在这一刻:

client.Shutdown(SocketShutdown.Both);
客户端.关闭();

此解决方案有效(wifi 模块对我的命令作出反应,但异常不令我满意)。这是我的代码,感谢您的帮助:

using System.Text;
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SDK_TestApp
{

public class Electricity
{
    private const int port = 2000;
    private static ManualResetEvent connectDone = new ManualResetEvent(false);
    private static ManualResetEvent sendDone = new ManualResetEvent(false);
    private static ManualResetEvent receiveDone = new ManualResetEvent(false);
    private static String response = String.Empty;

    public bool Start(String commande)
    {
        try
        {

            System.Net.IPAddress ipAddress = System.Net.IPAddress.Parse("192.168.1.17");

            IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);

            Socket theClient = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            theClient.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), theClient);

            connectDone.WaitOne();

            Receive(theClient);
            receiveDone.WaitOne();

            Console.WriteLine("Connexion : {0}", response);

            Send(theClient, commande);
            sendDone.WaitOne();

            Receive(theClient);
            receiveDone.WaitOne();

            Console.WriteLine("Response received : {0}", response);

            theClient.Shutdown(SocketShutdown.Both);
            theClient.Close();

            return true;

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            return false;
        }
    }

    private static void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            Socket client = (Socket)ar.AsyncState;

            client.EndConnect(ar);

            connectDone.Set();

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void Receive(Socket client)
    {
        try
        {

            StateObject state = new StateObject();
            state.workSocket = client;

            client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void ReceiveCallback(IAsyncResult ar)
    {
        try
        {

            StateObject state = (StateObject)ar.AsyncState;

            Socket clientReceiveCB = state.workSocket;

            SocketError test;

            int bytesRead = clientReceiveCB.EndReceive(ar, out test);

            Console.WriteLine("test endReceive : " + test);

            string testResponse = Encoding.ASCII.GetString(state.buffer, 0, bytesRead); 
            state.sb.Append(testResponse);

            clientReceiveCB.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);      

            if (state.sb.Length > 1)
            {
                response = state.sb.ToString();
            }

            receiveDone.Set();

        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

    private static void Send(Socket client, String data)
    {

        byte[] byteData = Encoding.ASCII.GetBytes(data);
        client.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), client);

    }

    private static void SendCallback(IAsyncResult ar)
    {
        try
        {
            Socket client = (Socket)ar.AsyncState;

            client.EndSend(ar);

            sendDone.Set();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
    }

}

public class StateObject
{
    public Socket workSocket = null;
    public const int BufferSize = 256;
    public byte[] buffer = new byte[BufferSize];
    public StringBuilder sb = new StringBuilder();
}

}

感谢任何帮助/解释:)

【问题讨论】:

  • 你的“此时此刻”有两条指令。错误发生在哪一个?
  • 我不确定,如果我评论这两行,我不会再有任何错误,如果我评论第一行,总是同样的错误,如果我评论第二行,我出现此错误:“System.Net.Sockets.SocketException (0x80004005): Une demande d'envoi ou de réception de données n'a pas été autorisée car le socket avait déjà été éteint dans cette direction par un appel d'arrêt précédent” (法语)

标签: c# multithreading sockets asynchronous


【解决方案1】:

如果您阅读documentation,它指出如果套接字在接收挂起时关闭,则ObjectDisposedExceptionEndReceive() 方法的预期结果。这是套接字通知您的应用程序BeginReceive() 操作结束的原因是因为套接字已关闭的方式。

除了try..catch 异常,没有什么可做的,并执行您可能需要做的任何清理工作。

更新

我还注意到您对线程的处理有点不寻常。在这个应用程序中,您使用的是异步方法(BeginConnect()BeginReceive()),但是您手动阻塞主线程,直到每个都使用 ManualResetEvents 完成。

从代码的外观来看,您似乎想要连接和阻塞,直到您读取服务器的响应,所以我建议将异步方法更改为同步方法(Connect()Receive())并执行Start 方法中的所有内容。这不仅可以消除您在一个线程上关闭套接字而另一个线程正在读取它时遇到的问题,而且会使代码更加简洁。

【讨论】:

  • 感谢您的快速回复,我想我必须使用异步方式,因为该软件可能能够同时与多个 wi-fi 模块通信
猜你喜欢
  • 2020-04-28
  • 1970-01-01
  • 2010-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-30
  • 1970-01-01
相关资源
最近更新 更多