服務端:javascript
1 namespace WebSocketServerEx 2 { 3 public class OpCode 4 { 5 public const sbyte Plain = -2; // defined by SuperWebSocket, to support hybi-00 6 public const string PlainTag = "-2"; 7 8 public const sbyte Handshake = -1; // defined by SuperWebSocket 9 public const string HandshakeTag = "-1"; 10 11 public const sbyte Continuation = 0; 12 public const string ContinuationTag = "0"; 13 14 public const sbyte Text = 1; 15 public const string TextTag = "1"; 16 17 public const sbyte Binary = 2; 18 public const string BinaryTag = "2"; 19 20 public const sbyte Close = 8; 21 public const string CloseTag = "8"; 22 23 public const sbyte Ping = 9; 24 public const string PingTag = "9"; 25 26 public const sbyte Pong = 10; 27 public const string PongTag = "10"; 28 } 29 30 public partial class Form1 : Form 31 { 32 private Thread thMain = null; 33 private Thread thFlashServer = null; 34 private Thread thClear = null; 35 private Dictionary<string, TcpClient> listMainTcp = new Dictionary<string, TcpClient>(); 36 private List<TcpClient> listFlashTcp = new List<TcpClient>(); 37 private Dictionary<string, Thread> listths = new Dictionary<string, Thread>(); 38 39 private ManualResetEvent tcpClientConnected = new ManualResetEvent(false); 40 private ManualResetEvent tcpClientConnectedflash = new ManualResetEvent(false); 41 42 public bool IsOnline(TcpClient c) 43 { 44 return !((c.Client.Poll(1000, SelectMode.SelectRead) && (c.Client.Available == 0)) || !c.Client.Connected); 45 } 46 public Form1() 47 { 48 InitializeComponent(); 49 } 50 51 private void Form1_Load(object sender, EventArgs e) 52 { 53 txtIP.Text = GetLocalIP(); 54 txtPort.Text = "8888"; 55 } 56 57 private void WebSocketMain() 58 { 59 //實例化服務器本機的端點 60 IPEndPoint local = new IPEndPoint(IPAddress.Parse(txtIP.Text), Convert.ToInt32(txtPort.Text)); 61 //定義服務器監聽對象 62 TcpListener listener = new TcpListener(local); 63 //開始監聽 64 listener.Start(); 65 66 thMain = new Thread(() => 67 { 68 while (true) 69 { 70 try 71 { 72 tcpClientConnected.Reset(); 73 listener.BeginAcceptTcpClient(clientConnect, listener); 74 tcpClientConnected.WaitOne(); 75 } 76 catch (Exception ex) 77 { 78 WriteLog("Error", "WebSocketMain " + ex.Message); 79 } 80 } 81 }); 82 83 thMain.Start(); 84 } 85 86 private void clientConnect(IAsyncResult ar) 87 { 88 try 89 { 90 TcpListener listener = (TcpListener)ar.AsyncState; 91 //接受客戶的鏈接,獲得鏈接的Socket 92 TcpClient client = listener.EndAcceptTcpClient(ar); 93 client.ReceiveBufferSize = 524288; 94 client.SendBufferSize = 524288; 95 Console.WriteLine("t " + client.Available); 96 int maxi = 0; 97 while (IsOnline(client) && maxi <= 1000) 98 { 99 maxi++; 100 Console.WriteLine("max " + maxi); 101 if (client.Available > 0) 102 { 103 BinaryReader reader = new BinaryReader(client.GetStream()); 104 BinaryWriter writer = new BinaryWriter(client.GetStream()); 105 106 Console.WriteLine("33"); 107 108 byte[] buffer = new byte[client.Available]; 109 reader.Read(buffer, 0, client.Available); 110 String result = Encoding.UTF8.GetString(buffer); 111 if (result.IndexOf("Sec-WebSocket-Key") >= 0) 112 { 113 writer.Write(PackHandShakeData(GetSecKeyAccetp(result))); 114 writer.Flush(); 115 116 lock (listMainTcp) 117 { 118 if (!listMainTcp.ContainsValue(client)) 119 { 120 listMainTcp.Add(client.Client.RemoteEndPoint.ToString(), client); 121 } 122 } 123 124 cmbClient.Invoke(new Action(() => 125 { 126 cmbClient.Items.Add(client.Client.RemoteEndPoint.ToString()); 127 })); 128 129 WriteLog("Info", "websocket 握手成功!" + client.Client.RemoteEndPoint); 130 } 131 132 Thread th = new Thread(() => 133 { 134 while (true) 135 { 136 try 137 { 138 if (client.Available > 0) 139 { 140 byte[] buffers = new byte[client.Available]; 141 reader.Read(buffers, 0, client.Available); 142 result = AnalyticData(buffers, buffers.Length); 143 WriteLog("Info", "來自客戶端[" + client.Client.RemoteEndPoint + "]消息" + result); 144 145 if (result == "\u0003�") 146 { 147 lock (listMainTcp) 148 { 149 listMainTcp.Remove(client.Client.RemoteEndPoint.ToString()); 150 } 151 lock (listths) 152 { 153 listths.Remove(client.Client.RemoteEndPoint.ToString()); 154 } 155 client.Close(); 156 break; 157 } 158 } 159 } 160 catch (ThreadAbortException e) 161 { 162 163 } 164 catch (Exception ex) 165 { 166 WriteLog("Error", "th " + ex.Message); 167 } 168 } 169 }); 170 th.Name = client.Client.RemoteEndPoint.ToString(); 171 listths.Add(th.Name, th); 172 th.Start(); 173 174 break; 175 } 176 } 177 } 178 catch 179 { 180 } 181 finally 182 { 183 tcpClientConnected.Set(); 184 } 185 } 186 187 private void FlashSocketServer() 188 { 189 //實例化服務器本機的端點 190 IPEndPoint local = new IPEndPoint(IPAddress.Parse(txtIP.Text), 843); 191 //定義服務器監聽對象 192 TcpListener listener = new TcpListener(local); 193 //開始監聽 194 listener.Start(); 195 196 TcpClient client = null; 197 BinaryReader reader = null; 198 BinaryWriter writer = null; 199 thFlashServer = new Thread(() => 200 { 201 while (true) 202 { 203 try 204 { 205 client = listener.AcceptTcpClient(); 206 Console.WriteLine("1 t" + client.Available); 207 int maxi = 0; 208 while (IsOnline(client) && maxi <= 1000) 209 { 210 maxi++; 211 Console.WriteLine("max2 " + maxi); 212 if (client.Available > 0) 213 { 214 lock (listFlashTcp) 215 { 216 if (!listFlashTcp.Contains(client)) 217 { 218 listFlashTcp.Add(client); 219 } 220 } 221 222 reader = new BinaryReader(client.GetStream()); 223 writer = new BinaryWriter(client.GetStream()); 224 225 226 byte[] buffer = new byte[client.Available]; 227 reader.Read(buffer, 0, client.Available); 228 String result = Encoding.UTF8.GetString(buffer); 229 if (result.IndexOf("<policy-file-request/>") >= 0) 230 { 231 byte[] datas = System.Text.Encoding.UTF8.GetBytes("<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"*\" /></cross-domain-policy>\0"); 232 writer.Write(datas); 233 writer.Flush(); 234 WriteLog("Info", "843端口握手成功!" + client.Client.RemoteEndPoint); 235 } 236 237 break; 238 } 239 } 240 } 241 catch (Exception ex) 242 { 243 WriteLog("Error", "thFlashServer " + ex.Message); 244 } 245 } 246 }); 247 thFlashServer.Start(); 248 } 249 250 private void tClear() 251 { 252 thClear = new Thread(() => 253 { 254 while (true) 255 { 256 Thread.Sleep(10000); 257 258 try 259 { 260 lock (listMainTcp) 261 { 262 if (listMainTcp.Count > 0) 263 { 264 string[] keys = new string[listMainTcp.Count]; 265 listMainTcp.Keys.CopyTo(keys, 0); 266 foreach (string key in keys) 267 { 268 if (listMainTcp[key] != null) 269 { 270 if (!IsOnline(listMainTcp[key])) 271 { 272 listths[key].Abort(); 273 listths.Remove(key); 274 275 cmbClient.Invoke(new Action(() => 276 { 277 cmbClient.Items.Remove(key); 278 })); 279 280 listMainTcp[key].Close(); 281 listMainTcp[key] = null; 282 listMainTcp.Remove(key); 283 } 284 } 285 } 286 } 287 } 288 289 lock (listFlashTcp) 290 { 291 if (listFlashTcp.Count > 0) 292 { 293 for (int i = 0; i < listFlashTcp.Count; i++) 294 { 295 if (listFlashTcp[i] != null) 296 { 297 if (!IsOnline(listFlashTcp[i])) 298 { 299 listFlashTcp[i].Close(); 300 listFlashTcp.Remove(listFlashTcp[i]); 301 } 302 } 303 } 304 } 305 } 306 } 307 catch (Exception ex) 308 { 309 WriteLog("Error", "tClear " + ex.Message); 310 } 311 } 312 }); 313 thClear.Start(); 314 } 315 316 private void Form1_FormClosed(object sender, FormClosedEventArgs e) 317 { 318 try 319 { 320 lock (listths) 321 { 322 listths.Clear(); 323 } 324 } 325 catch { } 326 327 try 328 { 329 thMain.Abort(); 330 thFlashServer.Abort(); 331 thClear.Abort(); 332 333 thMain = null; 334 thFlashServer = null; 335 thClear = null; 336 } 337 catch { } 338 339 try 340 { 341 lock (listMainTcp) 342 { 343 listMainTcp.Clear(); 344 } 345 346 lock (listFlashTcp) 347 { 348 listFlashTcp.Clear(); 349 } 350 } 351 catch { } 352 } 353 354 private void Form1_FormClosing(object sender, FormClosingEventArgs e) 355 { 356 if (MessageBox.Show("您肯定要關閉嗎,關閉後相關服務不可用!", "提示", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1) == DialogResult.Yes) 357 { 358 e.Cancel = false; 359 } 360 else 361 { 362 e.Cancel = true; 363 WriteLog("Fatal", "試圖關閉本程序!"); 364 } 365 } 366 private void WriteLog(string type, string t) 367 { 368 if (!txtLog.IsDisposed) 369 { 370 try 371 { 372 txtLog.Invoke(new Action(() => 373 { 374 txtLog.AppendText(Environment.NewLine); 375 txtLog.AppendText(string.Format("[{0}] [{1}] {2}", type, DateTime.Now.ToString(), t)); 376 })); 377 } 378 catch { } 379 } 380 } 381 382 /// <summary> 383 /// 打包握手信息 384 /// </summary> 385 /// <param name="secKeyAccept">Sec-WebSocket-Accept</param> 386 /// <returns>數據包</returns> 387 private byte[] PackHandShakeData(string secKeyAccept) 388 { 389 var responseBuilder = new StringBuilder(); 390 responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + Environment.NewLine); 391 responseBuilder.Append("Upgrade: websocket" + Environment.NewLine); 392 responseBuilder.Append("Connection: Upgrade" + Environment.NewLine); 393 responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine + Environment.NewLine); 394 //若是把上一行換成下面兩行,纔是thewebsocketprotocol-17協議,但竟然握手不成功,目前仍沒弄明白! 395 //responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine); 396 //responseBuilder.Append("Sec-WebSocket-Protocol: chat" + Environment.NewLine); 397 398 return Encoding.UTF8.GetBytes(responseBuilder.ToString()); 399 } 400 401 /// <summary> 402 /// 生成Sec-WebSocket-Accept 403 /// </summary> 404 /// <param name="handShakeText">客戶端握手信息</param> 405 /// <returns>Sec-WebSocket-Accept</returns> 406 private string GetSecKeyAccetp(String handShakeText) 407 { 408 string key = string.Empty; 409 Regex r = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n"); 410 Match m = r.Match(handShakeText); 411 if (m.Groups.Count != 0) 412 { 413 key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim(); 414 } 415 byte[] encryptionString = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); 416 return Convert.ToBase64String(encryptionString); 417 } 418 419 /// <summary> 420 /// 解析客戶端數據包 421 /// </summary> 422 /// <param name="recBytes">服務器接收的數據包</param> 423 /// <param name="recByteLength">有效數據長度</param> 424 /// <returns></returns> 425 private static string AnalyticData(byte[] recBytes, int recByteLength) 426 { 427 if (recByteLength < 2) { return string.Empty; } 428 429 bool fin = (recBytes[0] & 0x80) == 0x80; // 1bit,1表示最後一幀 430 if (!fin) 431 { 432 return string.Empty;// 超過一幀暫不處理 433 } 434 435 bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩碼 436 if (!mask_flag) 437 { 438 return string.Empty;// 不包含掩碼的暫不處理 439 } 440 441 int payload_len = recBytes[1] & 0x7F; // 數據長度 442 443 byte[] masks = new byte[4]; 444 byte[] payload_data; 445 446 if (payload_len == 126) 447 { 448 Array.Copy(recBytes, 4, masks, 0, 4); 449 payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]); 450 payload_data = new byte[payload_len]; 451 Array.Copy(recBytes, 8, payload_data, 0, payload_len); 452 453 } 454 else if (payload_len == 127) 455 { 456 Array.Copy(recBytes, 10, masks, 0, 4); 457 byte[] uInt64Bytes = new byte[8]; 458 for (int i = 0; i < 8; i++) 459 { 460 uInt64Bytes[i] = recBytes[9 - i]; 461 } 462 UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0); 463 464 payload_data = new byte[len]; 465 for (UInt64 i = 0; i < len; i++) 466 { 467 payload_data[i] = recBytes[i + 14]; 468 } 469 } 470 else 471 { 472 Array.Copy(recBytes, 2, masks, 0, 4); 473 payload_data = new byte[payload_len]; 474 Array.Copy(recBytes, 6, payload_data, 0, payload_len); 475 476 } 477 478 for (var i = 0; i < payload_len; i++) 479 { 480 payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]); 481 } 482 483 return Encoding.UTF8.GetString(payload_data); 484 } 485 486 private string GetLocalIP() 487 { 488 try 489 { 490 string HostName = Dns.GetHostName(); //獲得主機名 491 IPHostEntry IpEntry = Dns.GetHostEntry(HostName); 492 for (int i = 0; i < IpEntry.AddressList.Length; i++) 493 { 494 //從IP地址列表中篩選出IPv4類型的IP地址 495 //AddressFamily.InterNetwork表示此IP爲IPv4, 496 //AddressFamily.InterNetworkV6表示此地址爲IPv6類型 497 if (IpEntry.AddressList[i].AddressFamily == AddressFamily.InterNetwork) 498 { 499 return IpEntry.AddressList[i].ToString(); 500 } 501 } 502 return ""; 503 } 504 catch (Exception ex) 505 { 506 WriteLog("Error", "獲取本機IP出錯:" + ex.Message); 507 return ""; 508 } 509 } 510 511 /// <summary> 512 /// 可傳輸超長數據 513 /// </summary> 514 /// <param name="opCode"></param> 515 /// <param name="data"></param> 516 /// <param name="offset"></param> 517 /// <param name="length"></param> 518 /// <returns></returns> 519 private byte[] GetPackageData(int opCode, byte[] data, int offset, int length) 520 { 521 byte[] fragment; 522 523 if (length < 126) 524 { 525 fragment = new byte[2 + length]; 526 fragment[1] = (byte)length; 527 } 528 else if (length < 65536) 529 { 530 fragment = new byte[4 + length]; 531 fragment[1] = (byte)126; 532 fragment[2] = (byte)(length / 256); 533 fragment[3] = (byte)(length % 256); 534 } 535 else 536 { 537 fragment = new byte[10 + length]; 538 fragment[1] = (byte)127; 539 540 int left = length; 541 int unit = 256; 542 543 for (int i = 9; i > 1; i--) 544 { 545 fragment[i] = (byte)(left % unit); 546 left = left / unit; 547 548 if (left == 0) 549 break; 550 } 551 } 552 553 fragment[0] = (byte)(opCode | 0x80); 554 555 if (length > 0) 556 { 557 Buffer.BlockCopy(data, offset, fragment, fragment.Length - length, length); 558 } 559 560 return fragment; 561 } 562 563 private void BtnStart_Click(object sender, EventArgs e) 564 { 565 WriteLog("Info", "啓動 FlashSocketServer"); 566 FlashSocketServer(); 567 568 WriteLog("Info", "啓動 WebSocketMain"); 569 WebSocketMain(); 570 571 WriteLog("Info", "開始監聽..."); 572 tClear(); 573 } 574 575 private void btnSend_Click(object sender, EventArgs e) 576 { 577 try 578 { 579 if (cmbClient.SelectedIndex > -1) 580 { 581 TcpClient client = listMainTcp[cmbClient.SelectedItem.ToString()]; 582 if (client != null) 583 { 584 if (IsOnline(client)) 585 { 586 BinaryWriter writer = new BinaryWriter(client.GetStream()); 587 byte[] playloadData = Encoding.UTF8.GetBytes(txtmsg.Text); 588 var fragment = GetPackageData(OpCode.Text, playloadData, 0, playloadData.Length); 589 writer.Write(fragment); 590 } 591 } 592 } 593 } 594 catch (Exception ex) 595 { 596 WriteLog("Error", "send " + ex.Message); 597 } 598 } 599 } 600 }
客戶端:html
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Sample of web_socket.js</title> <!-- Include these three JS files: --> <script type="text/javascript" src="swfobject.js"></script> <script type="text/javascript" src="web_socket.js"></script> <script type="text/javascript"> // Set URL of your WebSocketMain.swf here: WEB_SOCKET_SWF_LOCATION = "WebSocketMain.swf"; // Set this to dump debug message from Flash to console.log: WEB_SOCKET_DEBUG = true; // Everything below is the same as using standard WebSocket. var ws; function init() { // Connect to Web Socket. // Change host/port here to your own Web Socket server. ws = new WebSocket("ws://127.0.0.1:8888/"); // Set event handlers. ws.onopen = function () { output("onopen"); }; ws.onmessage = function (e) { // e.data contains received string. output("onmessage: " + e.data); }; ws.onclose = function () { output("onclose"); }; ws.onerror = function () { output("onerror"); }; } function onSubmit() { var input = document.getElementById("input"); // You can send message to the Web Socket using ws.send. ws.send(input.value); output("send: " + input.value); input.value = ""; input.focus(); } function onCloseClick() { ws.close(); } function output(str) { var log = document.getElementById("log"); var escaped = str.replace(/&/, "&").replace(/</, "<"). replace(/>/, ">").replace(/"/, """); // " log.innerHTML = escaped + "<br>" + log.innerHTML; } </script> </head> <body onload="init();"> <form onsubmit="onSubmit(); return false;"> <input type="text" id="input"> <input type="submit" value="Send"> <button onclick="onCloseClick(); return false;">close</button> </form> <div id="log"></div> </body> </html>
服務端源碼:http://files.cnblogs.com/files/diose/WebSocketServerEx.zipjava
客戶端源碼:http://files.cnblogs.com/files/diose/ClientWebsocketDemo.zipios
如技術問題能夠諮詢:QQ 598181863web