c# websocket 服务端,客户端 兼容低版本IE,支持超长数据传输 附源码

服务端:

  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>");
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:(.*?)
");
410             Match m = r.Match(handShakeText);
411             if (m.Groups.Count != 0)
412             {
413                 key = Regex.Replace(m.Value, @"Sec-WebSocket-Key:(.*?)
", "$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>
<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(/&/, "&amp;").replace(/</, "&lt;").
              replace(/>/, "&gt;").replace(/"/, "&quot;"); // "
            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.zip

客户端源码:http://files.cnblogs.com/files/diose/ClientWebsocketDemo.zip

如技术问题可以咨询:QQ 598181863

原文地址:https://www.cnblogs.com/diose/p/7345879.html