前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[C#]UDP通讯

[C#]UDP通讯

作者头像
祥知道
发布2020-03-10 15:07:42
1.1K0
发布2020-03-10 15:07:42
举报
文章被收录于专栏:祥的专栏祥的专栏祥的专栏

原创文章,欢迎转载。转载请注明:转载自 祥的博客

原文链接:http://blog.csdn.net/humanking7/article/details/51024884


UDP的作用不用多说,在C#中不用自己痛苦的调用套接字的API,有两种方式来实现:

  1. 直接使用Socket类
  2. 使用UdpClient类

UdpClient类对基础Socket进行了封装,简化了UDP的开发难度,提高了编程效率。

话不多说,先上图。

01
01

重点

这个程序中需要两个 UdpClient 对象,一个用于发送,一个用于接收,经测试,可以只用一个 UdpClient 对象同时进行收发,但是我的接收程序是开了一个线程,这样同时进行收和发,会出现一些问题。所以要用两个 UdpClient 对象,但是 UdpClient 不能同时绑定一个ip地址和端口。我为此还调试了半天,发现了这个现象。 先看代码:

    if (false == isBind)
    {//还没有绑定

        //============================
        //Bind UDP
        //============================
        //Get Local and Remote IP&Port
        IPAddress LocalIP = IPAddress.Parse(TxtBox_LocalIP.Text);//本地IP
        int LocalPort = Convert.ToInt32(TxtBox_LocalPort.Text);//本地Port
        m_LocalIPEndPoint = new IPEndPoint(LocalIP, LocalPort);//本地IP和Port



        //Bind
        m_UdpClientSend = new UdpClient(LocalPort);//Bind Send UDP = Local some IP&Port
        m_UdpClientReceive = new UdpClient(m_LocalIPEndPoint);//Bind Receive UDP = Local IP&Port

/*
发送的UdpClient对象是m_UdpClientSend,绑定的地址是 0.0.0.0:8010
接收的UdpClient对象是m_UdpClientReceive,绑定的地址是 10.13.68.220:8010
*/


        //============================
        //Start UDP Receive Thread
        //============================
        m_ReceThread = new Thread(new ThreadStart(ReceProcess));//线程处理程序为 ReceProcess
        m_ReceThread.IsBackground = true;//后台线程,前台线程GG,它也GG
        m_ReceThread.Start();

        //============================
        //界面处理
        //============================
        TxtBox_LocalPort.Enabled = false;
        BTN_Bind.Text = "UnBind";
        isBind = true;
    } 
    else
    {//已经绑定

        //关闭 UDP
        m_UdpClientSend.Close();
        m_UdpClientReceive.Close();

        //关闭 线程
        m_ReceThread.Abort();

        //界面处理
        TxtBox_LocalPort.Enabled = true;
        BTN_Bind.Text = "Binding";
        isBind = false;
    }

发送的UdpClient对象是m_UdpClientSend,绑定的地址是 0.0.0.0:8010 接收的UdpClient对象是m_UdpClientReceive,绑定的地址是 10.13.68.220:8010

接收时一定要用 m_UdpClientReceive 的,但是发送时,两个对象皆可以。

UDP的发送

发送需要对方的地址,这里的地址是 10.13.68.220:8080。 发送的代码:

private void BTN_Send_Click(object sender, EventArgs e)
        {
            if (isBind)
            {//绑定好,可发送


                IPAddress RemoteIP;   //远端 IP                
                int RemotePort;      //远端 Port
                IPEndPoint RemoteIPEndPoint; //远端 IP&Port

                if (IPAddress.TryParse(TxtBox_RemoteIP.Text, out RemoteIP) == false)//远端 IP
                {
                    MessageBox.Show("Remote IP is Wrong!", "Wrong");
                    return;
                }
                RemotePort = Convert.ToInt32(TxtBox_RemotePort.Text);//远端 Port
                RemoteIPEndPoint = new IPEndPoint(RemoteIP, RemotePort);//远端 IP和Port


                //Get Data
                byte[] sendBytes = System.Text.Encoding.Default.GetBytes(TxtBox_Send.Text);                
                int cnt = sendBytes.Length;

                if (0 == cnt)
                {
                    return;
                }

                //Send
                m_UdpClientSend.Send(sendBytes, cnt, RemoteIPEndPoint);
                //下面的代码也可以,但是接收和发送分开,更好
                //m_UdpClientReceive.Send(sendBytes, cnt, RemoteIPEndPoint);


                //CNT
                m_cntSend += cnt;
                SetCNTTextBox();
            } 
            else
            {
                MessageBox.Show("You need bind first!","UnBind");
            }
        }

核心代码就是一句:

m_UdpClientSend.Send(sendBytes, cnt, RemoteIPEndPoint);

其中

  • RemoteIPEndPoint 是记录目标机的IP和端口号的IPEndPoint类型变量
  • sendBytes是用于发送的 byte[] 数组
  • cnt 记录要发送的byte长度

UDP的接收

接收要开一个线程,用于接收数据

private Thread m_ReceThread;//接收线程

线程的设置,在绑定按钮的click响应函数中,在解绑和窗体关闭时,都要将线程关掉

if (false == isBind)
{//还没有绑定
    //other code
    //······

    //============================
    //Start UDP Receive Thread
    //============================
    m_ReceThread = new Thread(new ThreadStart(ReceProcess));//线程处理程序为 ReceProcess
    m_ReceThread.IsBackground = true;//后台线程,前台线程GG,它也GG
    m_ReceThread.Start();

    //other code
    //······
}
else
{
//已经绑定

     //关闭 UDP
     m_UdpClientSend.Close();
     m_UdpClientReceive.Close();

     //关闭 线程
     m_ReceThread.Abort();

     //界面处理
     TxtBox_LocalPort.Enabled = true;
     BTN_Bind.Text = "Binding";
     isBind = false;
}

线程设定为后台线程

m_ReceThread.IsBackground = true;

这样的好处是,当主线程结束时,这个线程也跟着结束,防止了没有释放线程带来的开销和bug

线程的处理函数代码如下:

/// <summary>
/// 在后台运行的接收线程
/// </summary>
private void ReceProcess()
{
    int cnt = 0;
    string receiveFromOld = "";
    string receiveFromNew = "";

    //定义IPENDPOINT,装载远程IP地址和端口 
    IPEndPoint remoteIpAndPort = new IPEndPoint(IPAddress.Any, 0);
    while (true)
    {
        byte[] ReceiveBytes = m_UdpClientReceive.Receive(ref remoteIpAndPort);

        cnt = ReceiveBytes.Length;
        receiveFromNew = remoteIpAndPort.ToString();
        if (!receiveFromNew.Equals(receiveFromOld))
        {
            receiveFromOld = receiveFromNew;
            string str_From = String.Format("\r\n【Receive from {0}】\r\n", receiveFromNew);

            TxtBox_Receive.Text += str_From;
        }

        string str = System.Text.Encoding.Default.GetString(ReceiveBytes, 0, cnt);

        //界面显示
        TxtBox_Receive.Text += str;
        m_cntReceive += cnt;
        SetCNTTextBox();
    }
}

其中要注意的就是接收函数 Receive()参数 ,这个这个参数是一个 IPEndPoint 变量,而且是一个 引用参数,它的初始化也很有讲究

IPEndPoint remoteIpAndPort = new IPEndPoint(IPAddress.Any, 0);

被函数 Receive() 调用后,remoteIpAndPort的值将会发生改变,得到发送方的IP地址和端口号,最后我通过 IPEndPoint 类的ToString()方法,将其打印出来,用于显示对方的IP。

【注意】: 发送数据给你的IP地址和端口,不一定是你要发送的远端IP地址和端口。而且你可以接收到任何一个IP地址和端口发送的数据。

···
byte[] ReceiveBytes = m_UdpClientReceive.Receive(ref remoteIpAndPort);
···
string str_From = String.Format("\r\n【Receive from {0}】\r\n", receiveFromNew);
···
这里写图片描述
这里写图片描述
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 重点
  • UDP的发送
  • UDP的接收
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档