原文链接:
http://blog.csdn.net/humanking7/article/details/51024884
UDP的作用不用多说,在C#中不用自己痛苦的调用套接字的API,有两种方式来实现:
-
直接使用Socket类
-
使用UdpClient类
UdpClient类对基础Socket进行了封装,简化了UDP的开发难度,提高了编程效率。
话不多说,先上图。
这个程序中需要两个
UdpClient
对象,一个用于发送,一个用于接收,经测试,可以只用一个
UdpClient
对象同时进行收发,但是我的接收程序是开了一个线程,这样同时进行收和发,会出现一些问题。所以要用两个
UdpClient
对象,但是
UdpClient
不能同时绑定一个ip地址和端口
。我为此还调试了半天,发现了这个现象。
先看代码:
if
(
false
==
isBind)
{
IPAddress LocalIP
=
IPAddress
.
Parse(TxtBox_LocalIP
.
Text);
int LocalPort
=
Convert
.
ToInt32(TxtBox_LocalPort
.
Text);
m_LocalIPEndPoint
=
new
IPEndPoint(LocalIP, LocalPort);
m_UdpClientSend
=
new
UdpClient(LocalPort);
m_UdpClientReceive
=
new
UdpClient(m_LocalIPEndPoint);
发送的UdpClient对象是m_UdpClientSend,绑定的地址是 0.0.0.0:8010
接收的UdpClient对象是m_UdpClientReceive,绑定的地址是 10.13.68.220:8010
m_ReceThread
=
new
Thread
(
new
ThreadStart(ReceProcess));
m_ReceThread
.
IsBackground
=
true
;
m_ReceThread
.
Start();
TxtBox_LocalPort
.
Enabled
=
false
;
BTN_Bind
.
Text
=
"UnBind"
;
isBind
=
true
;
{
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;
int RemotePort;
IPEndPoint RemoteIPEndPoint;
if (IPAddress.TryParse(TxtBox_RemoteIP.Text, out RemoteIP) == false)
MessageBox.Show("Remote IP is Wrong!", "Wrong");
return;
RemotePort = Convert.ToInt32(TxtBox_RemotePort.Text);
RemoteIPEndPoint = new IPEndPoint(RemoteIP, RemotePort);
byte[] sendBytes = System.Text.Encoding.Default.GetBytes(TxtBox_Send.Text);
int cnt = sendBytes.Length;
if (0 == cnt)
return;
m_UdpClientSend.Send(sendBytes, cnt, RemoteIPEndPoint);
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)
{
m_ReceThread = new Thread(new ThreadStart(ReceProcess));
m_ReceThread.IsBackground = true;
m_ReceThread.Start();
m_UdpClientSend.Close();
m_UdpClientReceive.Close();
m_ReceThread.Abort();
TxtBox_LocalPort.Enabled = true;
BTN_Bind.Text = "Binding";
isBind = false;
线程设定为后台线程
m_ReceThread.IsBackground = true;
这样的好处是,当主线程结束时,这个线程也跟着结束,防止了没有释放线程带来的开销和bug
线程的处理函数代码如下:
private void ReceProcess()
int cnt = 0;
string receiveFromOld = "";
string receiveFromNew = "";
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);
原创文章,欢迎转载。转载请注明:转载自 祥的博客原文链接:http://blog.csdn.net/humanking7/article/details/51024884UDP的作用不用多说,在C#中不用自己痛苦的调用套接字的API,有两种方式来实现:直接使用Socket类使用UdpClient类UdpClient类对基础Socket进行了封装,简化了UDP的开发难度,提高了编程效率。话不多说
richTextBox1.Text = string.Empty;
//实例化UdpClient对象
UdpClient udpclient = new UdpClient(Convert.ToInt32(textBox2.Text));
//调用UdpClient对象的Connect建立默认远程主机
udpclient.Connect(textBox1.Text, Convert.ToInt32(textBox2.Text));
//定义一个字节数组,用来存放发送到远程主机的信息
Byte[] sendBytes = Encoding.Default.GetBytes(textBox3.Text);
//调用UdpClient对象的Send方法将Udp数据报发送到远程主机
udpclient.Send(sendBytes, sendBytes.Length);
//实例化IPEndPoint对象,用来显示响应主机的标识
IPEndPoint ipendpoint = new IPEndPoint(IPAddress.Any, 0);
//调用UdpClient对象的Receive方法获得从远程主机返回的Udp数据报
Byte[] receiveBytes = udpclient.Receive(ref ipendpoint);
使用Socket进行通信中,UDP是一种轻量级的无连接的通信协议。相对于TCP的安全可靠且又可以双工通信,UDP则更强调简单高效,而且利用UDP的无连接特性,我们可以穿透局域网,很多时候能够实现TCP无法实现的功能。
本文共分为三个部分:
第一部分 UDP的基本通信开始方法。
第二部分 UDP公网通信测试
第三部分 双局域网不利用第三方公共服务器实现直接通信。
这是第一部分。
全文主要的实现方法为...
1、UDP(User Data Protocol,用户数据报协议)
(1) UDP是一个非连接的协议,传输数据之前源端和终端不建立连接,当它想传送时就简单地去抓取来自应用程序的数据,并尽可能快地把它扔到网络上。在发送端,UDP传送数据的速度仅仅是受应用程序生成数据的速度、计算机的能力和传输带宽的限制;在接收端,UDP把每个消息段放在队列中,应用程序每次从队列中读一个消息段。
(2) 由于传输数据
之前困恼了很久的问题,终于解决了,项目要求使用Upd传输,128000的采样率 ,每次一个通道2000个数据,一个数据用3个字节传输,共8通道,最后两字节验证码,最后计算转成double值,用曲线显示并保存文件。
128000/2000=62(次)
1/62≈0.016(s)=16(ms)
200038+2=48002(字节)
相当于循环16ms传输48002个字节。
在之前的项目中,没有解决,让c++的同事写的插件,空闲时还是要自己研究下哈,但是资料真的好难找,最后自己摸索,实现了,下面把帮助类贴
UDP不属于面向连接的通信,在选择使用协议的时候,选择UDP必须要谨慎。在网络质量令人十分不满意的环境下,UDP协议数据包丢失会比较严重。但是由于UDP的特性:它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。比如我们聊天用的ICQ和QQ就是使用的UDP协议。
我们通过UDP进
// 构造一个远程终结点
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, 11000);
// 发送数据
string message = "hello, world";
byte[] data = Encoding.UTF8.GetBytes(message);
udpClient.Send(data, data.Length, ipEndPoint);
// 接收数据
byte[] receiveBytes = udpClient.Receive(ref ipEndPoint);
string receiveMessage = Encoding.UTF8.GetString(receiveBytes);
Console.WriteLine($"Received: {receiveMessage}");
catch (Exception e)
Console.WriteLine(e.ToString());
finally
udpClient.Close();
Console.ReadLine();
在这个示例中,我们创建了一个UdpClient对象,并绑定了本地端口11000。然后构造了一个远程终结点,将数据发送给远程终结点,接收远程终结点返回的数据。在发送数据时,我们将字符串转换成字节数组,使用UdpClient的Send方法发送;在接收数据时,我们调用UdpClient的Receive方法,该方法返回一个字节数组,我们将其转换成字符串并输出。最后关闭UdpClient对象并等待用户按下Enter键退出程序。