1.程序说明

今天学了C#的UDP,实现了一个非常简单的UDP收发工具

这个工具的功能就是发送UDP报文和监听UDP报文。在左侧的文本框中输入文字,单击“发送数据”按钮发送UDP报文。如果这个时候点击了右边的“接收数据”按钮,右边的文本框会显示左边发送的数据。右侧的按钮,按一次开始监听,按第二次终止监听。

2.控件布局

程序的控件布局如下图

3.程序代码

程序的C#代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using System.Windows.Forms;
  10. //本段代码中需要新增加的命名空间
  11. using System.Net.Sockets;
  12. using System.Net;
  13. using System.Threading;
  14. namespace UDPTest
  15. {
  16. public partial class FormMain : Form
  17. {
  18. public FormMain()
  19. {
  20. InitializeComponent();
  21. }
  22. /// <summary>
  23. /// 用于UDP发送的网络服务类
  24. /// </summary>
  25. private UdpClient udpcSend;
  26. /// <summary>
  27. /// 用于UDP接收的网络服务类
  28. /// </summary>
  29. private UdpClient udpcRecv;
  30. /// <summary>
  31. /// 按钮:发送数据
  32. /// </summary>
  33. /// <param name=”sender”></param>
  34. /// <param name=”e”></param>
  35. private void btnSend_Click(object sender, EventArgs e)
  36. {
  37. if (string.IsNullOrWhiteSpace(txtSendMssg.Text))
  38. {
  39. MessageBox.Show(“请先输入待发送内容”);
  40. return;
  41. }
  42. // 匿名发送
  43. //udpcSend = new UdpClient(0); // 自动分配本地IPv4地址
  44. // 实名发送
  45. IPEndPoint localIpep = new IPEndPoint(
  46. IPAddress.Parse(“127.0.0.1”), 12345); // 本机IP,指定的端口号
  47. udpcSend = new UdpClient(localIpep);
  48. Thread thrSend = new Thread(SendMessage);
  49. thrSend.Start(txtSendMssg.Text);
  50. }
  51. /// <summary>
  52. /// 发送信息
  53. /// </summary>
  54. /// <param name=”obj”></param>
  55. private void SendMessage(object obj)
  56. {
  57. string message = (string)obj;
  58. byte[] sendbytes = Encoding.Unicode.GetBytes(message);
  59. IPEndPoint remoteIpep = new IPEndPoint(
  60. IPAddress.Parse(“127.0.0.1”), 8848); // 发送到的IP地址和端口号
  61. udpcSend.Send(sendbytes, sendbytes.Length, remoteIpep);
  62. udpcSend.Close();
  63. ResetTextBox(txtSendMssg);
  64. }
  65. /// <summary>
  66. /// 开关:在监听UDP报文阶段为true,否则为false
  67. /// </summary>
  68. bool IsUdpcRecvStart = false;
  69. /// <summary>
  70. /// 线程:不断监听UDP报文
  71. /// </summary>
  72. Thread thrRecv;
  73. /// <summary>
  74. /// 按钮:接收数据开关
  75. /// </summary>
  76. /// <param name=”sender”></param>
  77. /// <param name=”e”></param>
  78. private void btnRecv_Click(object sender, EventArgs e)
  79. {
  80. if (!IsUdpcRecvStart) // 未监听的情况,开始监听
  81. {
  82. IPEndPoint localIpep = new IPEndPoint(
  83. IPAddress.Parse(“127.0.0.1”), 8848); // 本机IP和监听端口号
  84. udpcRecv = new UdpClient(localIpep);
  85. thrRecv = new Thread(ReceiveMessage);
  86. thrRecv.Start();
  87. IsUdpcRecvStart = true;
  88. ShowMessage(txtRecvMssg, “UDP监听器已成功启动”);
  89. }
  90. else // 正在监听的情况,终止监听
  91. {
  92. thrRecv.Abort(); // 必须先关闭这个线程,否则会异常
  93. udpcRecv.Close();
  94. IsUdpcRecvStart = false;
  95. ShowMessage(txtRecvMssg, “UDP监听器已成功关闭”);
  96. }
  97. }
  98. /// <summary>
  99. /// 接收数据
  100. /// </summary>
  101. /// <param name=”obj”></param>
  102. private void ReceiveMessage(object obj)
  103. {
  104. IPEndPoint remoteIpep = new IPEndPoint(IPAddress.Any, 0);
  105. while (true)
  106. {
  107. try
  108. {
  109. byte[] bytRecv = udpcRecv.Receive(ref remoteIpep);
  110. string message = Encoding.Unicode.GetString(
  111. bytRecv, 0, bytRecv.Length);
  112. ShowMessage(txtRecvMssg,
  113. string.Format(“{0}[{1}]”, remoteIpep, message));
  114. }
  115. catch (Exception ex)
  116. {
  117. ShowMessage(txtRecvMssg, ex.Message);
  118. break;
  119. }
  120. }
  121. }
  122. // 向TextBox中添加文本
  123. delegate void ShowMessageDelegate(TextBox txtbox, string message);
  124. private void ShowMessage(TextBox txtbox, string message)
  125. {
  126. if (txtbox.InvokeRequired)
  127. {
  128. ShowMessageDelegate showMessageDelegate = ShowMessage;
  129. txtbox.Invoke(showMessageDelegate, new object[] { txtbox, message });
  130. }
  131. else
  132. {
  133. txtbox.Text += message + “\r\n”;
  134. }
  135. }
  136. // 清空指定TextBox中的文本
  137. delegate void ResetTextBoxDelegate(TextBox txtbox);
  138. private void ResetTextBox(TextBox txtbox)
  139. {
  140. if (txtbox.InvokeRequired)
  141. {
  142. ResetTextBoxDelegate resetTextBoxDelegate = ResetTextBox;
  143. txtbox.Invoke(resetTextBoxDelegate, new object[] { txtbox });
  144. }
  145. else
  146. {
  147. txtbox.Text = “”;
  148. }
  149. }
  150. /// <summary>
  151. /// 关闭程序,强制退出
  152. /// </summary>
  153. /// <param name=”sender”></param>
  154. /// <param name=”e”></param>
  155. private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
  156. {
  157. Environment.Exit(0);
  158. }
  159. }
  160. }


4.其他

在关闭UdpClient(调用它的Close函数)前,一定要先关闭监听UDP的线程,否则会报错:“一个封锁操作被对 WSACancelBlockingCall 的调用中断”。

END

转载于:https://my.oschina.net/Tsybius2014/blog/351974