3-_-3 2018-04-13 15:28 采纳率: 50%
浏览 1899
已结题

在多线程环境下使用udpclient进行异步UDP接收出现“访问已注销对象”的异常,怎么办?

最近打算使用C#写一个仿飞秋的局域网即时通信工具,但是在使用多线程异步收发UDP数据时老是出现“访问对象已注销”的异常,查了好久都没有找到原因,只能求助于网友啦。
完整代码可以在我的github上下载:WAW
说说具体情况吧:
1.为了进行udp数据的异步接收,我写了一个异步接收类AsyncUDPclient。

  public class AsyncUDPclient
    {
        private IPEndPoint recEP, sendEP;
        private UdpClient udpReceive, udpSend;
        private UdpState udpReceiveState, udpSendState;

        //定义消息接收事件
        public event MessageReceivedEventHandle MessageReceived;

        // 异步状态同步
        //private ManualResetEvent sendDone = new ManualResetEvent(false);
        //private ManualResetEvent receiveDone = new ManualResetEvent(false);

        public AsyncUDPclient()
        {
            recEP = new IPEndPoint(IPAddress.Any, InfoSet.IpPort.Port);//允许从任意远程主机终节点接收数据
            sendEP = new IPEndPoint(IPAddress.Any, InfoSet.IpPort.Port);//允许向任意远程主机终节点发送数据,发送和接收使用同一个端口
            udpReceive = new UdpClient(recEP);
            udpSend = new UdpClient();

            udpReceiveState = new UdpState();
            udpReceiveState.udpClient = udpReceive;
            udpReceiveState.ipEndPoint = recEP;

            udpSendState = new UdpState();
            udpSendState.udpClient = udpSend;
            udpSendState.ipEndPoint = sendEP;
        }

        public void ReceiveMsg()
        {
            udpReceive.BeginReceive(new AsyncCallback(ReceiveCallback), udpReceiveState);
            //receiveDone.WaitOne();
        }

        private void ReceiveCallback(IAsyncResult iar)
        {
            UdpState s = iar.AsyncState as UdpState;
            if(iar.IsCompleted)
            {
                IPEndPoint ep = s.ipEndPoint;
                UdpClient u = s.udpClient;
                Byte[] receiveBytes = u.EndReceive(iar, ref ep);

                //调用消息接收事件处理方法
                MessageEventArgs args = new MessageEventArgs();
                args.remoteIP = ep;
                args.buffer = receiveBytes;
                if (MessageReceived != null)
                {
                    MessageReceived(this, args);
                }
                //receiveDone.Set();

                u.BeginReceive(new AsyncCallback(ReceiveCallback), s);//此处需要验证s.ipEndPoint的值是否已经变化?
            }
        }

        public void SendMsg(byte[] datagram,int bytes,IPEndPoint sendEP)
        {
            udpSendState.ipEndPoint = sendEP;
            udpSend.BeginSend(datagram, bytes,sendEP, new AsyncCallback(SendCallback), udpSendState);
            Thread.Sleep(100);
        }

        private void SendCallback(IAsyncResult iar)
        {
            UdpState s = iar.AsyncState as UdpState;
            s.udpClient.EndSend(iar);
            //sendDone.Set();
        }

        public void StopClient()
        {
            udpSend.Close();
            udpReceive.Close();
            Thread.Sleep(100);
        }
    }

    /// <summary>
    /// 消息接收事件委托
    /// </summary>
    /// <param name="Sender"></param>
    /// <param name="e"></param>
    public delegate void MessageReceivedEventHandle(object Sender, MessageEventArgs e);
    public class MessageEventArgs : EventArgs
    {
        public byte[] buffer;
        public IPEndPoint remoteIP;

        public MessageEventArgs() : base()
        {
            remoteIP = new IPEndPoint(IPAddress.Any, 0);
        }
    }
    public class UdpState
    {
        public UdpClient udpClient;
        public IPEndPoint ipEndPoint;
    }

2.当程序启动之后,在程序主窗口类frmMain.cs里开了一个新线程监听指定端口,用于接收UDP数据,然后主窗口程序广播上线消息。

     public partial class frmMain : Form
    {
        //用于整个程序收发数据的对象
        public AsyncUDPclient AsyncUDP;

        private Thread udplistenthread;
        private DataReceive startreceive;

        public frmMain()
        {
            InitializeComponent();
            _userstate = wawState.SignIn;
            Rectangle rec = Screen.GetWorkingArea(this);
            this.ClientSize = new Size(234, rec.Height - 100);
            this.Location = new Point((int)(rec.Width * 0.8), (int)(rec.Height * 0.05));
            this.MaximumSize = new Size(260, rec.Height);
            this.MinimumSize = new Size(234, 100);
            this.chTag.Width = 0;
            this.chUser.Width = (int)(this.lvwUsers.Width * 0.3);
            this.chIP.Width = (int)(this.lvwUsers.Width * 0.4);
            this.chHostname.Width = this.lvwUsers.Width - this.chUser.Width - this.chHostname.Width;

            AsyncUDP = new AsyncUDPclient();//收发数据对象初始化
        }

        private void frmMain_Load(object sender, EventArgs e)
        {
            //开启监听线程,新线程执行StartListenUdp方法
            startreceive = new DataReceive(lvwUsers, lblUserCount,AsyncUDP);
            udplistenthread = new Thread(new ThreadStart(startreceive.StartListenUdp));
            udplistenthread.IsBackground = true;
            udplistenthread.Start();

            MsgBoardCast boardcast = new MsgBoardCast(AsyncUDP);
            //boardcast.BoardCast(wawCMD.WAW_BC_SIGNIN);

            int i = 0;
            foreach(IPAddress addr in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
            {
                if(addr.AddressFamily==AddressFamily.InterNetwork)
                {
                    cmbIpList.Items.Add(addr.ToString());
                    if (addr.ToString()==InfoSet.IpPort.Address.ToString())
                    {
                        cmbIpList.SelectedIndex = i;
                    }
                    i++;                    
                }
            }
        }
        }

StartListenUdp方法如下(就是调用异步接收类AsyncUDPclient的ReceiveMsg方法开始异步接收):

        public void StartListenUdp()
        {          
            AsyncClient.MessageReceived += new MessageReceivedEventHandle(DataConfig);
            AsyncClient.ReceiveMsg();
        }

但是在运行过程中一直很出现异常,貌似是说调用udpclient对象是该对象已经注销,但我检查了很久都没有查处问题,这个问题一直卡了我整整两周时间,实在是没办法了。
以下是调试报错截图:
图片说明

  • 写回答

3条回答

  • devmiao 2018-04-13 15:52
    关注
    评论

报告相同问题?

悬赏问题

  • ¥15 安卓adb backup备份应用数据失败
  • ¥15 eclipse运行项目时遇到的问题
  • ¥15 关于#c##的问题:最近需要用CAT工具Trados进行一些开发
  • ¥15 南大pa1 小游戏没有界面,并且报了如下错误,尝试过换显卡驱动,但是好像不行
  • ¥15 没有证书,nginx怎么反向代理到只能接受https的公网网站
  • ¥50 成都蓉城足球俱乐部小程序抢票
  • ¥15 yolov7训练自己的数据集
  • ¥15 esp8266与51单片机连接问题(标签-单片机|关键词-串口)(相关搜索:51单片机|单片机|测试代码)
  • ¥15 电力市场出清matlab yalmip kkt 双层优化问题
  • ¥30 ros小车路径规划实现不了,如何解决?(操作系统-ubuntu)