UDP数据传输实例

下面通过一个例子,对UdpClient类的用法及它的一些方法进行说明。在UDP模式下,不存在明显的服务器与客户端之分,所以在这里用A端和B端代替。本例要实现的功能是从A端到B端的点对点通信。打开VS2008,在D:C#ch17目录下建立名为P2PTest的Windows应用程序。打开工程,为当前窗体添加如表17-9所示控件。

  表17-9 添加控件列表

控件名 Name Text
Label Label1 对方IP:
TextBox tbIP  
TextBox tbMsg  
Button btnSend 发送
ListBox lbInfo  
GroupBox gbSend 发送窗口
GroupBox gbReceive 接收窗口
Button btnClear 清空

  本例是利用8888端口进行局域网内部的点对点通信,只要确认对方IP,就能相互发送信息。代码的添加主要分为以下步骤。

  (1)首先是对几个命名空间的引用,包括System.Net、System.Net.Sockets和System.Threading。然后定义如下三个全局变量。

双击代码全选
1
2
3
4
5
private UdpClient uc;
  
private IPEndPoint iep;
  
private Thread th;

 

  其中UdpClient是本例的核心成员,主要通过它的相关方法进行数据的收发。

  (2)本例使用8888端口进行通信,所以应该在当前窗体构造函数Form1()内,用该端口实例化UdpClient。

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
public Form1()
  
    {
  
      InitializeComponent();
  
CheckForIllegalCrossThreadCalls = false;
  
      uc = new UdpClient(8888);
  
    }

 

  CheckForIllegalCrossThreadCalls主要是解决线程间的控件操作问题,通过将其属性设置为fasle,可以禁用对操作控件的线程是否为创建该窗体的线程的检测,阻止该异常的发生。这种问题在第16章中也遇到过,当时是采用的委托的方法进行解决。

  (3)双击“发送”按钮,添加如下代码。

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
iep = new IPEndPoint(IPAddress.Parse(tbIP.Text), 8888);
  
th = new Thread(new ThreadStart(listen));
  
th.IsBackground = true;                 //设置在后台运行
  
th.Start();                        //启动线程
  
string temp = tbMsg.Text;
  
byte[] b = Encoding.UTF8.GetBytes(temp);  //对发送的数据的进行UTF8格式的编码 
  
uc.Send(b, b.Length,iep);               //发送数据

 

  其中listen()方法用于监听对方发送过来的消息,实现代码如下。

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void listen()
  
{
  
  while (true)
  
  {
  
    string text = Encoding.UTF8.GetString(uc.Receive(ref iep));  //对发送的数据的进行UTF8格式的编码
  
    lbInfo.Items.Add(text + "n");
  
  }
  
}

 

  (4)双击“清空”按钮,添加如下代码。

双击代码全选
1
lbInfo.Items.Clear();

 

  (5)最后还需要进行一些资源释放的操作。

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected override void Dispose(bool disposing)
  
{
  
  if (disposing && (components != null))
  
  {
  
    components.Dispose();
  
    th.Abort();                    //关闭线程
  
    uc.Close();                    //关闭UdpClient
  
  }
  
  base.Dispose(disposing);
  
}

 

  完成以上操作后,将该软件放在两台计算机之间进行测试。

  在测试过程中,发送的数据有时不能被对方收到。这是UDP本身的特性造成的,因为UDP是不可靠的传输协议,这也是基于UDP通信的缺点之一。

  在上面的例子中,收发数据用到了UdpClient类的几种方法,如Send()和Receive(),下面对这些方法进行详细说明。

  首先看发送数据用到的Send()方法,它具有以下重载形式。

双击代码全选
1
2
3
4
5
public int Send(byte[] dgram,int bytes);
  
public int Send(byte[] dgram,int bytes,string hostname,int port);
  
public int Send(byte[] dgram,int bytes);

其中,dgram表示需要发送的数据,它必须满足字节数组的格式;bytes表示该字节数组的长度;hostname和port指需要接收数据的主机名和端口号。

  接着是接收数据用到的Receive()方法,它没有重载形式,声明如下。

双击代码全选
1
public byte[] Receive(ref IPEndPoint remoteEP);

 

  这里需要注意的是它的参数是引用类型,且remoteEP应该取发送方的IP和端口号。

  JoinMulticastGroup()方法能将UdpClient类添加到多路广播组,它的用法如下所示。

双击代码全选
1
2
3
4
5
public void JoinMulticastGroup(IPAddress multicastAddr);
  
public void JoinMulticastGroup(IPAddress multicastAddr,int timeToLive);
  
public void JoinMulticastGroup(int ifindex,IPAddress multicastAddr);

 

  multicastAddr和前面所提到的IPAddress的实例有了本质区别,它不再是单个主机的IP地址,而是一个广播地址。如果将IP中标识主机的部分全置“1”,即表示该网络的广播地址。比如校园网常用的C类地址,只要将最后8位全部置“1”即可得到本地网络中的广播地址。它的优势是能实现广播的功能,比如从A端发出数据,在B、C、D、E端等都能同时接收,而不是像上个例子中必须指定接收方的IP。timeToLive是按路由器跳数测量的TTL。

  JoinMulticastGroup()的用法比较简单,如下所示。

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System.Net;
  
using System.Net.Sockets;
  
……
  
UdpClient uc = new UdpClient();
  
IPAddress bcip =IPAddress.Parse("222.18.142.255"); //C类IP的广播地址
  
try
  
{
  
  uc.JoinMulticastGroup(bcip,20);            //添加到多路组播
  
}
  
catch(Exception ex)
  
{
  
  Console.WriteLine(ex.Message);
  
}

 

  DropMulticastGroup()方法进行与JoinMulticastGroup()方法相反的操作,用法如下所示。

双击代码全选
1
public void DropMulticastGroup (IPAddress multicastAddr);

 

  本节到目前为止,主要介绍了UdpClient类的用法,其实直接用Socket类也能完成同样的功能。鉴于篇幅有限,就不再详述。只是有一点需要指出,利用Socket连接创建基于UDP的通信时,它的实例化方法应与TCP进行区别,如下所示。

双击代码全选
1
Socket s = new Socket(AddressFamily.InterNetwork,SocketType.Dgram, ProtocolType.Udp);

 

  后面两个参数发生了变化,SocketType的类型选择Dgram,表示数据传输是以数据报的形式而非流;协议类型需要选择Udp。

  UDP与TCP相比,在某些方面较有优势。比如它的实时性比TCP要好,它不需握手、差错检验和流的控制;它产生的负载很少等。它的缺点是数据传输不可靠。

 

 

posted on 2012-05-31 17:08  peter_zhang  阅读(4901)  评论(3编辑  收藏  举报