C#UDP通讯UdpClient

 
    class UdpClientClass
    {
        /// <summary>
        /// 构建客户端
        /// </summary>
        /// <param name="servierIpAddress">服务器iP地址或者域名</param>
        /// <param name="sevierPort">服务器监听端口</param>
        /// <param name="locadPort">本地监听端口</param>
        /// <param name="timeOut">超时等待时间</param>
        public UdpClientClass(string servierIpAddress, int sevierPort, int locadPort, int timeOut)
        {
            if (FpHelper.CheckIpAddress(ref servierIpAddress) == true)
            {
                try
                {
                    ServerIPE = new IPEndPoint(IPAddress.Parse(servierIpAddress), sevierPort);
                    UdpListenClient = new UdpClient(locadPort);//固定通信端口
                    UdpListenClient.Client.ReceiveTimeout = 3000;
                    const long IOC_IN = 0x80000000;
                    const long IOC_VENDOR = 0x18000000;
                    const long SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;

                    byte[] optionInValue = { Convert.ToByte(false) };
                    byte[] optionOutValue = new byte[4];

                    UdpListenClient.Client.IOControl((IOControlCode)SIO_UDP_CONNRESET, optionInValue, optionOutValue);

                   
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show("绑定端口失败" + ex.Message.ToString());
                }

            }
        }

        /// <summary>
        /// UDP发送类,绑定了一个固定的端口
        /// </summary>
        private static UdpClient UdpListenClient;

        public event EventHandler MessageChanged;

        /// <summary>
        /// 接收到服务器消息改变后触发的事件
        /// </summary>
        /// <param name="user"></param>
        public void OnMessageChanged(UdpClientClass fp)
        {
            if (MessageChanged != null)
            {
                MessageChanged(fp, null);
            }
        }

        /// <summary>
        /// 服务器端的IP与端口
        /// </summary>
        private IPEndPoint ServerIPE = null;

        bool IsReceiving = false;

        public void Send(byte[] data, int len)
        {
          int len1 =  UdpListenClient.Send(data, len, ServerIPE);
            if (!IsReceiving)
                StartAndLsn();
        }

        private Thread ClientRecThread;

        private void StartAndLsn()
        {
            IsReceiving = true;
            ClientRecThread = new Thread(new ThreadStart(RecF));//启动新线程做接收
            ClientRecThread.IsBackground = true;
            ClientRecThread.Start();

        }//启动并且 监听 服务器发来的数据


        private void RecF()//接收数据做服务
        {
            byte[] btRec = null;
            while (IsReceiving)
            {
                IPEndPoint remoteIPE = new IPEndPoint(IPAddress.Any, 0);
                btRec = UdpListenClient.Receive(ref remoteIPE);//UDP接收数据
                if (btRec.Length > 0 && remoteIPE.Address == ServerIPE.Address)//只处理特定的服务端的数据
                {
                    System.Windows.Forms.MessageBox.Show("res");
                }
                else
                {
                }

            }
        }//循环接收数据
    }

遇到如下两个问题

1.UdpListenClient.Receive接受数据位阻塞模式,一直等待对方的返回,网上询问这个问题的很多,解答的却很多答非所问,仔细查看了UdpClient 类发现里面有一个Socket熟悉,
关于通讯的底层问题都通过该熟悉来设置,该熟悉又设置发送或者接受超时的设置,如
UdpListenClient.Client.ReceiveTimeout = 3000;//设置超时接收返回
2.udp通讯发现有时会产生

远程主机强迫关闭了一个现有的连接的错误

网上查找了很多,终于看到一篇

在公司一项目的UDP消息服务开发中时不时的会遇到这样一个问题:在UDP通信过程中,如果客户端中途断开,服务器会收到一个SocketException,错误ID为10054,描述是“远程主机强迫关闭了一个现有的连接”,紧接着的事就可怕了,UDP服务终止监听,所有客户端都受到了影响。也就是说一个客户端引起的异常导致了整个系统的崩溃。这个问题可是太严重了。

地球人都知道,UDP是无连接的,怎么会出现这个异常呢?百度了一圈,发现有这个问题的现象还不少,可就是没有一个有效的回复。再GOOGLE一圈,有点眉目了。找到了一个微软的解释和一个DOTNET的解决方法:

微软的解释:http://support.microsoft.com/kb/263823

DOTNET的处理方法:http://www.devnewsgroups.net/group/microsoft.public.dotnet.framework/topic1887.aspx

不过处理方法似乎对参数的设置不太正确: byte[] optionInValue = { Convert.ToByte(true) }; byte[] optionOutValue;

按照这样设置还是会抛出该异常。 首先,根据微软的解释,optionInValue 传入的应该是false,而不是true; 其次,根据微软的解释,optionOutValue应该是一个DWORD值,不应不赋值,或设为null。

根据以上两点,将以上两句改为: byte[] optionInValue = { Convert.ToByte(false) }; byte[] optionOutValue = new byte[4];

经过测试,模拟500个用户进行登录、收发消息、注销、异常退出、再连接,均没有再抛出该异常。服务表现稳定。

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值