說明:
通過建立本地UdpClient與遠程UdpClient進行通訊,亦可直接發送到其他已存在的遠程端。
基本原理:構建一個本地的udpcSend實例,開啟多線程進行監聽,然后再發送廣播。
案例有字節數組與十六進制字符串相互轉換的方法。
一、案例源碼
窗體的主要代碼:FrmMain.cs
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.Net; 8 using System.Net.Sockets; 9 using System.Text; 10 using System.Threading; 11 using System.Threading.Tasks; 12 using System.Windows.Forms; 13 14 namespace NetworkService 15 { 16 public partial class FrmMain : Form 17 { 18 public FrmMain() 19 { 20 InitializeComponent(); 21 22 //string msg = "FF FB 0F"; 23 //byte[] bytes = Encoding.Default.GetBytes(msg); 24 25 26 //string res = ""; 27 //for (int i = 0; i < bytes.Length; i++) 28 //{ 29 // res += bytes[i].ToString(); 30 //} 31 //MessageBox.Show(res); 32 33 34 } 35 36 //本地收發UDPClient實例 37 private UdpClient udpcSend; 38 private UdpClient udpcRecv; 39 private bool isLocalConneted = false;//本地是否已連接 40 private Thread thrRecv;//本地監聽接收線程 41 42 /// <summary> 43 /// 【構建本地連接】 44 /// 20181021 45 /// </summary> 46 /// <param name="sender"></param> 47 /// <param name="e"></param> 48 private void btnConnect_Click(object sender, EventArgs e) 49 { 50 if (cbProtocol.SelectedIndex != 0) 51 { 52 MessageBox.Show("請暫時選擇UDP協議!", "系統提示"); 53 return; 54 } 55 56 if (string.IsNullOrWhiteSpace(tbLocalIP.Text) || string.IsNullOrWhiteSpace(tbLocalPort.Text)) 57 { 58 MessageBox.Show("請填寫本地IP和端口", "系統提示"); 59 return; 60 } 61 62 63 if (!isLocalConneted)//構建本地連接 64 { 65 IPEndPoint localIpep = new IPEndPoint(IPAddress.Parse(tbLocalIP.Text), Convert.ToInt32(tbLocalPort.Text)); 66 udpcSend = new UdpClient(localIpep); 67 68 btnConnect.Text = "斷開"; 69 isLocalConneted = true; 70 71 //啟動監聽接收信息 72 BeginListenRecv(); 73 } 74 else//斷開本地連接 75 { 76 //關閉監聽線程 77 thrRecv.Abort(); 78 udpcRecv.Close(); 79 80 udpcSend.Close(); 81 btnConnect.Text = "連接"; 82 isLocalConneted = false; 83 84 85 ShowMessage(tbRecvMsg, "[OS]:UDP監聽已成功關閉"); 86 } 87 } 88 89 90 91 /// <summary> 92 /// 【開始監聽】 93 /// 20181021 94 /// </summary> 95 private void BeginListenRecv() 96 { 97 udpcRecv = udpcSend;//接收與發送使用同一個實例 98 99 thrRecv = new Thread(ReceiveMessage); 100 thrRecv.Start(); 101 102 ShowMessage(tbRecvMsg, "[OS]:Local UDP 監聽已成功啟動"); 103 104 } 105 106 /// <summary> 107 /// 【接收信息】 108 /// 20181021 109 /// </summary> 110 private void ReceiveMessage() 111 { 112 IPEndPoint remoteIpep = new IPEndPoint(IPAddress.Any, 0);//接收任何來源的信息 113 while (true) 114 { 115 byte[] byteRecv = udpcRecv.Receive(ref remoteIpep); 116 string message = ByteArrayToHexStringNoBlank(byteRecv); 117 118 //remoteIpep.Address.ToString() 獲取發送源的IP 119 ShowMessage(tbRecvMsg, "[Local Recv]:" + remoteIpep.Address + ":" + remoteIpep.Port + "=" + message); 120 121 } 122 123 } 124 125 /// <summary> 126 /// 【發送消息】 127 /// 20181021 128 /// </summary> 129 /// <param name="obj"></param> 130 private void SendMessage(object obj) 131 { 132 string[] data = (string[])obj; 133 134 //字符串轉16進制 135 byte[] sendBytes = HexStringToByteArray(data[0]); 136 137 //發送到遠程IP和端口 138 IPEndPoint remoteIpep = new IPEndPoint(IPAddress.Parse(data[1]), Convert.ToInt32(data[2])); 139 140 udpcSend.Send(sendBytes, sendBytes.Length, remoteIpep); 141 142 143 ShowMessage(tbRecvMsg, "[Local Send]:" + data[0]); 144 ResetTextBox(tbSendMsg); 145 } 146 147 148 //構建遠程服務的收發實例 149 private UdpClient remoteUdpcSend; 150 private UdpClient remoteUdpcRecv; 151 private Thread remoteThrRecv; 152 153 private Thread thrSend; 154 private bool isRemoteCreated = false; 155 /// <summary> 156 /// 【發送消息】 157 /// 20181021 158 /// </summary> 159 /// <param name="sender"></param> 160 /// <param name="e"></param> 161 private void btnSend_Click(object sender, EventArgs e) 162 { 163 if (string.IsNullOrWhiteSpace(tbRemoteIP.Text) || string.IsNullOrWhiteSpace(tbRemotePort.Text)) 164 { 165 MessageBox.Show("遠程IP和端口不能為空!", "系統提示"); 166 return; 167 } 168 169 if (string.IsNullOrWhiteSpace(tbSendMsg.Text)) 170 { 171 MessageBox.Show("發送的消息不能為空!", "系統提示"); 172 return; 173 } 174 175 if (!isLocalConneted) 176 { 177 MessageBox.Show("請先建立本地連接!", "系統提示"); 178 return; 179 } 180 181 182 //構建本地遠程 183 if (cbIsRemoteAsLocal.Checked)//構建本地的遠程服務,本地處理 184 { 185 if (!isRemoteCreated) 186 { 187 IPEndPoint remoteIpep = new IPEndPoint(IPAddress.Parse(tbRemoteIP.Text), Convert.ToInt32(tbRemotePort.Text));//構建遠程端口 188 remoteUdpcRecv = new UdpClient(remoteIpep); 189 190 //啟動遠程的監聽 191 remoteThrRecv = new Thread(RemoteRecvMessage); 192 remoteThrRecv.Start(); 193 194 ShowMessage(tbRecvMsg, "[OS]:Remote UDP 監聽啟動完成!"); 195 isRemoteCreated = true;//遠程服務已啟動 196 } 197 else 198 { 199 //發送消息 200 } 201 202 } 203 else 204 { 205 //發送消息, 206 } 207 208 //發送遠程,這里不做處理,直接調用udpcSend發送即可 209 thrSend = new Thread(new ParameterizedThreadStart(SendMessage)); 210 211 string[] param = new string[] { tbSendMsg.Text, tbRemoteIP.Text, tbRemotePort.Text }; 212 thrSend.Start(param); 213 214 } 215 216 /// <summary> 217 /// 【本地遠程發送消息】 218 /// 20181021 219 /// </summary> 220 /// <param name="remoteIpep"></param> 221 private void RemoteSendMessage(IPEndPoint remoteIpep) 222 { 223 remoteUdpcSend = remoteUdpcRecv; 224 225 byte[] msg = Encoding.Default.GetBytes("遠程已收到你的消息"); 226 227 remoteUdpcSend.Send(msg, msg.Length, remoteIpep); 228 229 ShowMessage(tbRecvMsg, "[Remote Send]:" + "遠程已收到你的消息"); 230 } 231 232 /// <summary> 233 /// 【本地遠程接收信息】 234 /// 20181021 235 /// </summary> 236 private void RemoteRecvMessage() 237 { 238 IPEndPoint remoteIpep = new IPEndPoint(IPAddress.Any, 0);//接收任何來源的信息 239 while (true) 240 { 241 byte[] byteRemoteRecv = remoteUdpcRecv.Receive(ref remoteIpep); 242 string message = Encoding.Default.GetString(byteRemoteRecv); 243 244 //接收到信息 245 if (byteRemoteRecv.Length > 0) 246 { 247 //remoteIpep.Address.ToString() 獲取發送源的IP 248 ShowMessage(tbRecvMsg, "[Remote Recv]:" + remoteIpep.Address + ":" + remoteIpep.Port + "=" + message); 249 250 RemoteSendMessage(remoteIpep); 251 } 252 253 } 254 } 255 256 //更新顯示TextBox 257 delegate void ShowMessageDelegate(TextBox tb, string msg); 258 private void ShowMessage(TextBox tb, string msg) 259 { 260 if (tb.InvokeRequired) 261 { 262 ShowMessageDelegate showMessageDelegate = ShowMessage; 263 tb.Invoke(showMessageDelegate, new object[] { tb, msg }); 264 } 265 else 266 { 267 tb.Text += msg + "\r\n"; 268 } 269 } 270 271 //清空TextBox 272 delegate void ResetTextBoxDelegate(TextBox tb); 273 private void ResetTextBox(TextBox tb) 274 { 275 if (tb.InvokeRequired) 276 { 277 ResetTextBoxDelegate resetTextBoxDelegate = ResetTextBox; 278 tb.Invoke(resetTextBoxDelegate, new object[] { tb }); 279 } 280 else 281 { 282 tb.Text = ""; 283 } 284 } 285 286 /// <summary> 287 /// 【字符串轉16進制】 288 /// 20181021 289 /// </summary> 290 /// <param name="s"></param> 291 /// <returns></returns> 292 public byte[] HexStringToByteArray(string s) 293 { 294 if (s.Length == 0) 295 throw new Exception("字符串長度為0"); 296 s = s.Replace(" ", ""); 297 byte[] buffer = new byte[s.Length / 2]; 298 for (int i = 0; i < s.Length; i += 2) 299 buffer[i / 2] = Convert.ToByte(s.Substring(i, 2), 16); 300 return buffer; 301 } 302 303 /// <summary> 304 /// 【字節數組轉換成十六進制字符串(不帶空格)】 305 /// 20181021 306 /// </summary> 307 /// <param name="data">要轉換的字節數組</param> 308 /// <returns>轉換后的字符串</returns> 309 public string ByteArrayToHexStringNoBlank(byte[] data) 310 { 311 StringBuilder sb = new StringBuilder(data.Length * 3); 312 foreach (byte b in data) 313 sb.Append(Convert.ToString(b, 16).PadLeft(2, '0') + " "); 314 return sb.ToString().ToUpper(); 315 } 316 317 /// <summary> 318 /// 【窗體退出,關閉子線程】 319 /// 20181021 320 /// </summary> 321 /// <param name="sender"></param> 322 /// <param name="e"></param> 323 private void FrmMain_FormClosing(object sender, FormClosingEventArgs e) 324 { 325 Environment.Exit(0); 326 } 327 328 329 330 331 } 332 }
二、界面