[C#]UDP通讯

原创文章,欢迎转载。转载请注明:转载自 祥的博客
原文链接: http://blog.csdn.net/humanking7/article/details/51024884
UDP的作用不用多说,在C#中不用自己痛苦的调用套接字的API,有两种方式来实现:
- 直接使用Socket类
- 使用UdpClient类
UdpClient类对基础Socket进行了封装,简化了UDP的开发难度,提高了编程效率。
话不多说,先上图。

重点
这个程序中需要两个
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;
{//已经绑定
//关闭 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();
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
//······
//已经绑定
//关闭 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();