当前位置: 代码迷 >> C# >> C#UDP点对多通信不能同时收到数据,点对点时运行没有关问题
  详细解决方案

C#UDP点对多通信不能同时收到数据,点对点时运行没有关问题

热度:56   发布时间:2016-05-05 03:35:03.0
C#UDP点对多通信不能同时收到数据,点对点时运行没问题。
之前我做的是点对点的电脑和设备通信可以通信(每个点收到我发的数据就会立即回复它的数据),UDP通信参照的方法是http://my.oschina.net/Tsybius2014/blog/351974。现在需要让电脑和多个这样的设备通信,于是我按照原来的方法增加了一个UDP通信,代码如下。
现在的问题是我定时器发送数据到两个点(这时候我一直监听两个接收端口),用两个线程接收,不能保证能收到两个的数据,有时候一直接收到1号的,2号的一直没有(偶尔一起接收到),后来有可能是一直接收到2号的,1号的不来了(偶尔一起接收到)。但是我只监听一个的话,就很正常,感觉就是两个一起监听,数据一起来接收的时候就出现上述情况。(我的发送没有问题,测试都能发出去。我把发送和接收端口都分开的


     //********************发送数据用定时器实现,每5秒触发一次。
   
        /// <summary>
        /// 自动发送计时器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void autoSendTimer1_Tick(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtSendMssg.Text))
            {
                MessageBox.Show("请先输入待发送内容");
                return;
            }
            string message = txtSendMssg.Text;
            byte[] sendbytes = Encoding.ASCII.GetBytes(message);

            IPEndPoint remoteIpep1 = new IPEndPoint(
                IPAddress.Parse("192.168.1.241"), 60001); // 发送到的IP地址和端口号****************************************
            try
            {
                udpcSend1.Send(sendbytes, sendbytes.Length, remoteIpep1);
            }
            catch
            { }
        }
        int count = 0;
        private void autoSendTimer2_Tick(object sender, EventArgs e)
        {
            string message = txtSendMssg.Text;
            byte[] sendbytes = Encoding.ASCII.GetBytes(message);
            
            IPEndPoint remoteIpep2 = new IPEndPoint(
                IPAddress.Parse("192.168.1.242"), 60002);// 发送到的IP地址和端口号****************************************
            try
            {
                udpcSend2.Send(sendbytes, sendbytes.Length, remoteIpep2);
                count = count + 1;//计数用于检验接收到数据的次数
                textBox10.Text = Convert.ToString(count);
            }
            catch
            { }
        }
      //***************************************接收数据,用两个线程分别接受
       /// <summary>
        /// 开关:在监听UDP报文阶段为true,否则为false
        /// </summary>
        bool IsUdpcRecvStart = false;
        bool IsUdpcRecvStart2 = false;
        /// <summary>
        /// 线程:不断监听UDP报文
        /// </summary>
        Thread thrRecv1;
        Thread thrRecv2;

        /// <summary>
        /// 按钮:接收数据开关
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnRecv1_Click(object sender, EventArgs e)
        {
            if (!IsUdpcRecvStart) // 未监听的情况,开始监听
            {
                try
                {
                    IPEndPoint localIpep1 = new IPEndPoint(
                        IPAddress.Parse(textBox11.Text), 10001); // 本机IP和监听端口号*****************************
                    //设置接收UDP监听
                    if (udpcRecv1 == null)
                        udpcRecv1 = new UdpClient(localIpep1);

                    IPEndPoint localIpep2 = new IPEndPoint(
                        IPAddress.Parse(textBox11.Text), 10100); // 本机IP,指定的发送端口号***********************************

                    //设置发送udp套接字
                    if (udpcSend1 == null)
                    {
                        udpcSend1 = new UdpClient(localIpep2);
                    }

                }
                catch{}
                thrRecv1 = new Thread(ReceiveMessage1);
                thrRecv1.Start();
                IsUdpcRecvStart = true;
            }
            else                  // 正在监听的情况,终止监听
            {
                if (thrRecv1 != null)
                    thrRecv1.Abort(); // 必须先关闭这个线程,否则会异常

                udpcRecv1.Close();
                udpcRecv1 = null;
                udpcSend1.Close();
                udpcSend1 = null;

                IsUdpcRecvStart = false;
            }
        }

        private void btnRecv2_Click(object sender, EventArgs e)
        {
            if (!IsUdpcRecvStart2) // 未监听的情况,开始监听
            {
                try
                {

                    IPEndPoint localIpep3 = new IPEndPoint(
                        IPAddress.Parse(textBox11.Text), 10002); // 本机IP和监听端口号*****************************
                    //设置接收UDP监听
                    if (udpcRecv2 == null)
                        udpcRecv2 = new UdpClient(localIpep3);

                    IPEndPoint localIpep4 = new IPEndPoint(
                        IPAddress.Parse(textBox11.Text), 10101);
                    //设置发送udp套接字

                    if (udpcSend2 == null)
                    {
                        udpcSend2 = new UdpClient(localIpep4);
                    }
                }
                catch{}
                thrRecv2 = new Thread(ReceiveMessage2);
                thrRecv2.Start();
                IsUdpcRecvStart2 = true;
            }
            else                  // 正在监听的情况,终止监听
            {

                if (thrRecv2 != null)
                    thrRecv2.Abort();

                udpcRecv2.Close();
                udpcRecv2 = null;
                udpcSend2.Close();
                udpcSend2 = null;
                IsUdpcRecvStart2 = false;
            }
        }
        /// <summary>
        /// 接收数据
        /// </summary>
        /// <param name="obj"></param>
        private void ReceiveMessage1(object obj)
        {
             IPEndPoint remoteIpep1 = new IPEndPoint(IPAddress.Any, 0);
             while (true)
            {
              byte[] bytRecv1 = udpcRecv1.Receive(ref remoteIpep1);
              //后面就是数据处理绘图了
            }
        }
        private void ReceiveMessage2(object obj)
        {
             IPEndPoint remoteIpep = new IPEndPoint(IPAddress.Any, 0);
             while (true)
            {
              byte[] bytRecv = udpcRecv.Receive(ref remoteIpep);
             //后面就是数据处理绘图了
            }
        }

------解决思路----------------------
用一个端口、两个端口、10万个端口收发消息,这没有什么差别。实际上你是用一个端口就可以了,没有必要用多个端口。

主要是你在”并发“发送。而udp本来就是不可靠的,可以随时丢掉消息。你在个人的、只有一个人的、慢速的、顺序的,总之是比较”理想化“的情况下的所谓”都很正常“,这是不可靠的说法,因为的代码本身就没有额外写上一大堆可靠性的逻辑(例如不断重发、二次验证等等)。udp经常丢包才是正常的。
------解决思路----------------------
IPAddress.Parse("192.168.1.241"), 60001)

不要这样写
你应该用IPAddress.Any,接收来自任何IP的数据包,而不是2个UDP对象各只接收来自其中1个IP的数据包

你接收到数据包之后,是有属性标明哪个IP哪个端口发送来的.
------解决思路----------------------
首先,同时发送,也不会同时到达
网卡在发送数据报的时候是将报自己的包放在线路中有报的间隔中的
就好比你的汽车要上路,必须等待能容纳你的车空隙出现时,才能加入整个车流
而每辆车都是可以唯一识别的,不会张冠李戴
所以程序在收到数据包时,是有函数获取来源ip的。不可能混淆
实在不放心,你也可以显式的在数据中加入标识宿主的关键字
  相关解决方案