WebSocket服务端 C#示例代码

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Net.Sockets;
  6. using System.Net;
  7. using System.Threading;
  8. using System.Text.RegularExpressions;
  9. using System.Security.Cryptography;
  10.  
  11. namespace WebSocketDemo
  12. {
  13. class Program
  14. {
  15. static void Main(string[] args)
  16. {
  17. int port = ;
  18. byte[] buffer = new byte[];
  19.  
  20. IPEndPoint localEP = new IPEndPoint(IPAddress.Any, port);
  21. Socket listener = new Socket(localEP.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
  22.  
  23. try
  24. {
  25. listener.Bind(localEP);
  26. listener.Listen();
  27.  
  28. Console.WriteLine("等待客户端连接....");
  29. Socket sc = listener.Accept();//接受一个连接
  30. Console.WriteLine("接受到了客户端:" + sc.RemoteEndPoint.ToString() + "连接....");
  31.  
  32. //握手
  33. int length = sc.Receive(buffer);//接受客户端握手信息
  34. sc.Send(PackHandShakeData(GetSecKeyAccetp(buffer, length)));
  35. Console.WriteLine("已经发送握手协议了....");
  36.  
  37. //接受客户端数据
  38. Console.WriteLine("等待客户端数据....");
  39. length = sc.Receive(buffer);//接受客户端信息
  40. string clientMsg = AnalyticData(buffer, length);
  41. Console.WriteLine("接受到客户端数据:" + clientMsg);
  42.  
  43. //发送数据
  44. string sendMsg = "您好," + clientMsg;
  45. Console.WriteLine("发送数据:“" + sendMsg + "” 至客户端....");
  46. sc.Send(PackData(sendMsg));
  47.  
  48. Console.WriteLine("演示Over!");
  49.  
  50. }
  51. catch (Exception e)
  52. {
  53. Console.WriteLine(e.ToString());
  54. }
  55. }
  56. /// <summary>
  57. /// 打包握手信息
  58. /// </summary>
  59. /// <param name="secKeyAccept"></param>
  60. /// <returns></returns>
  61. private static byte[] PackHandShakeData(string secKeyAccept)
  62. {
  63. var responseBuilder = new StringBuilder();
  64. responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + Environment.NewLine);
  65. responseBuilder.Append("Upgrade: websocket" + Environment.NewLine);
  66. responseBuilder.Append("Connection: Upgrade" + Environment.NewLine);
  67. responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine + Environment.NewLine);
  68. //如果把上一行换成下面两行,才是thewebsocketprotocol-17协议,但居然握手不成功,目前仍没弄明白!
  69. //responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine);
  70. //responseBuilder.Append("Sec-WebSocket-Protocol: chat" + Environment.NewLine);
  71.  
  72. return Encoding.UTF8.GetBytes(responseBuilder.ToString());
  73. }
  74.  
  75. /// <summary>
  76. /// 生成Sec-WebSocket-Accept
  77. /// </summary>
  78. /// <param name="handShakeText">客户端握手信息</param>
  79. /// <returns>Sec-WebSocket-Accept</returns>
  80. private static string GetSecKeyAccetp(byte[] handShakeBytes, int bytesLength)
  81. {
  82. string handShakeText = Encoding.UTF8.GetString(handShakeBytes, , bytesLength);
  83. string key = string.Empty;
  84. Regex r = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n");
  85. Match m = r.Match(handShakeText);
  86. if (m.Groups.Count != )
  87. {
  88. key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim();
  89. }
  90. byte[] encryptionString = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"));
  91. return Convert.ToBase64String(encryptionString);
  92. }
  93.  
  94. /// <summary>
  95. /// 解析客户端数据包
  96. /// </summary>
  97. /// <param name="recBytes">服务器接收的数据包</param>
  98. /// <param name="recByteLength">有效数据长度</param>
  99. /// <returns></returns>
  100. private static string AnalyticData(byte[] recBytes, int recByteLength)
  101. {
  102. if (recByteLength < ) { return string.Empty; }
  103.  
  104. bool fin = (recBytes[] & 0x80) == 0x80; // 1bit,1表示最后一帧
  105. if (!fin)
  106. {
  107. return string.Empty;// 超过一帧暂不处理
  108. }
  109.  
  110. bool mask_flag = (recBytes[] & 0x80) == 0x80; // 是否包含掩码
  111. if (!mask_flag)
  112. {
  113. return string.Empty;// 不包含掩码的暂不处理
  114. }
  115.  
  116. int payload_len = recBytes[] & 0x7F; // 数据长度
  117.  
  118. byte[] masks = new byte[];
  119. byte[] payload_data;
  120.  
  121. if (payload_len == )
  122. {
  123. Array.Copy(recBytes, , masks, , );
  124. payload_len = (UInt16)(recBytes[] << | recBytes[]);
  125. payload_data = new byte[payload_len];
  126. Array.Copy(recBytes, , payload_data, , payload_len);
  127.  
  128. }
  129. else if (payload_len == )
  130. {
  131. Array.Copy(recBytes, , masks, , );
  132. byte[] uInt64Bytes = new byte[];
  133. for (int i = ; i < ; i++)
  134. {
  135. uInt64Bytes[i] = recBytes[ - i];
  136. }
  137. UInt64 len = BitConverter.ToUInt64(uInt64Bytes, );
  138.  
  139. payload_data = new byte[len];
  140. for (UInt64 i = ; i < len; i++)
  141. {
  142. payload_data[i] = recBytes[i + ];
  143. }
  144. }
  145. else
  146. {
  147. Array.Copy(recBytes, , masks, , );
  148. payload_data = new byte[payload_len];
  149. Array.Copy(recBytes, , payload_data, , payload_len);
  150.  
  151. }
  152.  
  153. for (var i = ; i < payload_len; i++)
  154. {
  155. payload_data[i] = (byte)(payload_data[i] ^ masks[i % ]);
  156. }
  157.  
  158. return Encoding.UTF8.GetString(payload_data);
  159. }
  160.  
  161. /// <summary>
  162. /// 打包服务器数据
  163. /// </summary>
  164. /// <param name="message">数据</param>
  165. /// <returns>数据包</returns>
  166. private static byte[] PackData(string message)
  167. {
  168. byte[] contentBytes = null;
  169. byte[] temp = Encoding.UTF8.GetBytes(message);
  170.  
  171. if (temp.Length < )
  172. {
  173. contentBytes = new byte[temp.Length + ];
  174. contentBytes[] = 0x81;
  175. contentBytes[] = (byte)temp.Length;
  176. Array.Copy(temp, , contentBytes, , temp.Length);
  177. }
  178. else if (temp.Length < 0xFFFF)
  179. {
  180. contentBytes = new byte[temp.Length + ];
  181. contentBytes[] = 0x81;
  182. contentBytes[] = ;
  183. contentBytes[] = (byte)(temp.Length & 0xFF);
  184. contentBytes[] = (byte)(temp.Length >> & 0xFF);
  185. Array.Copy(temp, , contentBytes, , temp.Length);
  186. }
  187. else
  188. {
  189. // 暂不处理超长内容
  190. }
  191.  
  192. return contentBytes;
  193. }
  194. }
  195. }

HTML5 客户端示例代码

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8" />
  5. <title>WebSockets客户端示例</title>
  6. </head>
  7. <script>
  8. var webSocket;
  9. function connect()
  10. {
  11. try
  12. {
  13. var readyState = new Array("正在连接","已建立连接","正在关闭连接","已关闭连接");
  14. var host = "ws://localhost:10";
  15. webSocket = new WebSocket(host);
  16. var message = document.getElementById("message");
  17. message.innerHTML +="<p>Socket状态:" + readyState[webSocket.readyState] + "</p>";
  18. webSocket.onopen = function()
  19. {
  20. message.innerHTML += "<p>Socket状态:" + readyState[webSocket.readyState] + "</p>";
  21. }
  22. webSocket.onmessage = function(msg)
  23. {
  24. message.innerHTML +="<p>接收信息:" + msg.data + "</p>";
  25. }
  26. webSocket.onclose=function()
  27. {
  28. message.innerHTML +="<p>Socket状态:" + readyState[webSocket.readyState] + "</p>";
  29. }
  30. }
  31. catch(exception)
  32. {
  33. message.innerHTML += "<p>有错误发生</p>";
  34. }
  35. }
  36. function send()
  37. {
  38. var text = document.getElementById("text").value;
  39. var message = document.getElementById("message");
  40. if(text == "")
  41. {
  42. message.innerHTML += "<p>请输入一些文字</p>";
  43. return ;
  44. }
  45. try
  46. {
  47. webSocket.send(text);
  48. message.innerHTML += "<p>发送数据:" +text + "</p>";
  49. }
  50. catch(exception)
  51. {
  52. message.innerHTML += "<p>发送数据出错</p>";
  53. }
  54. document.getElementById("text").value="";
  55. }
  56. function disconnect()
  57. {
  58. webSocket.close();
  59. }
  60. </script>
  61. <body>
  62. <h1>WebSocket客户端示例</h1>
  63. <div id="message"></div>
  64. <p>请输入一些文字</p>
  65. <input id="text" type="text">
  66. <button id="connect" onClick="connect();">建立连接</button>
  67. <button id="send" onClick="send();">发送数据</button>
  68. <button id="disconnect" onClick="disconnect();">断开连接</button>
  69. </body>
  70. </html>

GitHub地址:BMBH/.NET-Demo

C# WebSocket模拟发送接收的更多相关文章

  1. C# Socket模拟发送接收

    Socket简介 通过TCP/IP与仪器或设备通讯,在C#语言中,我们通常采用Socket.本项目是一个简单的Socket建立服务监听与Socket作为客户端请求的一个示例. 项目结构 客户端项目 S ...

  2. C#小爬虫,通过URL进行模拟发送接收数据

    public async Task<string> SendDataAsync(HttpMethod httpMethod, string requestUrl, HttpContent ...

  3. C# 模拟串口发送接收

    一.准备虚拟串口驱动工具 创建俩个虚拟串口,如图: 二.创建两个控制台程序 模拟串口的发送接收数据 1. 接收数据,代码如下: //遍历串行端口名称数组 foreach (string port in ...

  4. 十一、模拟扫码登录微信(用Django简单的布置了下页面)发送接收消息

    为了能够模拟登陆QQ,并获取信息.对扫码登录微信进行了分析.简单的用了一下Django将获取的信息映射到页面上.(python3+pycharm) 主要过程就是: 1.获取二维码 2.扫码登录(有三种 ...

  5. 38KHz,NEC红外模拟发送和接收程序

    /*************************************************************************************************/ ...

  6. nodejs与websocket模拟简单的聊天室

    nodejs与websocket模拟简单的聊天室 server.js const http = require('http') const fs = require('fs') var userip ...

  7. PHP模拟发送POST请求之一、HTTP协议头部解析

    WEB开发中信息基本全是在POST与GET请求与响应中进行,GET因其基于URL的直观,易被我们了解,可POST请求因其信息的隐蔽,在安全的同时,也给开发者们模拟发送带来了麻烦.接下来的几篇博文中,我 ...

  8. 安卓Socket连接实现连接实现发送接收数据,openwrt wifi转串口连接单片机实现控制

    安卓Socket连接实现连接实现发送接收数据,openwrt wifi转串口连接单片机实现控制 socket 连接采用流的方式进行发送接收数据,采用thread线程的方式. 什么是线程?  详细代码介 ...

  9. outlook 2016 for windows 每次刷新发送接收邮件会弹出登陆界面

    Q: outlook2016 for windows 每次刷新发送接收邮件会弹出登陆界面,office365 ProPlus 都是正常激活了,Word 和Excel都不存在此类问题 A: 排除用户的o ...

随机推荐

  1. windows解决访问github慢问题

    ·1.更改host文件 文件地址: C:\Windows\System32\Drivers\etc ​ 如果不能直接修改,可拷贝到桌面修改后再复制回去 2.在host文件追加 ​ #github 19 ...

  2. org.yaml.snakeyaml.error.YAMLException: java.nio.charset.MalformedInputException: Input length = 1

    项目启动报错2018-12-21 14:06:24.917 INFO 23472 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refr ...

  3. TMS-规划图

    规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 规划图 ...

  4. 【C#复习总结】细说泛型委托

    1 前言 本系列会将[委托] [匿名方法][Lambda表达式] [泛型委托] [表达式树] [事件]等基础知识总结一下.(本人小白一枚,有错误的地方希望大佬指正) 系类1:细说委托 系类2:细说匿名 ...

  5. 深入理解Redis复制

    复制 A few things to understand ASAP about Redis replication. 1) Redis replication is asynchronous, bu ...

  6. ZooKeeper: 简介, 配置及运维指南

    1. 概览 ZooKeeper是一个供其它分布式应用程序使用的软件, 它为其它分布式应用程序提供所谓的协调服务. 所谓的协调服务, 是指ZooKeeper的如下能力 naming 命名 configu ...

  7. Wechart 饼图

    预览 Preview | Usage Source | Pie Source | Tutorial Wechart by Cax Cax 众所周知 Cax 既能开发游戏.又能开发图表.本文将从饼图开始 ...

  8. 【开源】小程序、小游戏和Web运动引擎 to2to 发布

    简单轻量跨平台的 Javascript 运动引擎 Github → https://github.com/dntzhang/cax/tree/master/packages/to Simple DEM ...

  9. SVM(支持向量机)之Hinge Loss解释

    Hinge Loss 解释 SVM 求解使通过建立二次规划原始问题,引入拉格朗日乘子法,然后转换成对偶的形式去求解,这是一种理论非常充实的解法.这里换一种角度来思考,在机器学习领域,一般的做法是经验风 ...

  10. pycharm 常用快捷键操作

    #最重要的快捷键 1. ctrl+shift+A:万能命令行 2. shift两次:查看资源文件 #新建工程第一步操作 1. module设置把空包分层去掉,compact empty middle ...