1、创建一个winform项目
2、创建websocket服务端类WebSocket_Service.cs
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Linq; 5 using System.Net; 6 using System.Net.Sockets; 7 using System.Security.Cryptography; 8 using System.Text; 9 using System.Text.RegularExpressions; 10 using System.Threading.Tasks; 11 12 namespace WSWin 13 { 14 /// <summary> 15 /// WebSocket 16 /// </summary> 17 public sealed class WebSocket_Service 18 { 19 20 byte[] buffer = new byte[1024]; 21 private Socket _listener = null;//服务端Socket 22 private readonly IPEndPoint _ip_port = null; 23 private readonly int _listen_count = 0; 24 private Action<Socket_CallBack_Type, Object, Socket> _callback = null; 25 public WebSocket_Service(IPEndPoint ip_port, Action<Socket_CallBack_Type, Object, Socket> callback, int listen_count = 100) 26 { 27 this._ip_port = ip_port; 28 this._callback = callback; 29 this._listen_count = listen_count; 30 } 31 /// <summary> 32 /// 启动监听 33 /// </summary> 34 public void Start() 35 { 36 if (this._listener == null) 37 this._listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 38 this._listener.Bind(this._ip_port); 39 this._listener.Listen(this._listen_count); 40 this.accept(); 41 } 42 /// <summary> 43 /// 等待连接 44 /// </summary> 45 private void accept() 46 { 47 Console.WriteLine("等待客户端连接...."); 48 Socket sc = _listener.Accept();//接受一个连接 49 Console.WriteLine("接受到了客户端:" + sc.RemoteEndPoint.ToString() + "连接...."); 50 this.Receive2HandShake(sc); 51 } 52 #region 正式接收客户端信息 53 private void Receive2Msg(Socket client) 54 { 55 Console.WriteLine("等待客户端数据...."); 56 int length = client.Receive(buffer);//接受客户端信息 57 if (length > 0) 58 { 59 string clientMsg = AnalyticData(buffer, length); 60 Console.WriteLine("接受到客户端数据:" + clientMsg); 61 if (clientMsg == @"Hello , I am Egret Test By Aonaufly") 62 { 63 this._callback(Socket_CallBack_Type.connect_succ, null, client);//发送连接成功信息 64 } 65 //this.Receive2Msg(client); 66 } 67 else 68 { 69 client.Disconnect(true); 70 } 71 } 72 #endregion 73 #region 向服务端发送信息 74 public void Send2Msg(Socket client, string clientMsg) 75 { 76 Console.WriteLine("==发送数据:" + clientMsg + " 至客户端...."); 77 byte[] body = Encoding.UTF8.GetBytes(clientMsg); 78 byte[] c = this.PackData(body); 79 Console.WriteLine("数据的大小 : {0} / 包的大小 : {1}", body.Length, c.Length); 80 client.Send(c); 81 } 82 #endregion 83 #region 接收客户端发来的握手信息并返回握手信息 84 /// <summary> 85 /// 第四次握手信息处理 86 /// </summary> 87 /// <param name="client"></param> 88 private void Receive2HandShake(Socket client) 89 { 90 int length = client.Receive(buffer); 91 if (length > 0) 92 { 93 client.Send(PackHandShakeData(GetSecKeyAccetp(buffer, length))); 94 Console.WriteLine("已经发送握手协议了...."); 95 this.Receive2Msg(client); 96 } 97 else 98 { 99 client.Disconnect(true); 100 } 101 } 102 #endregion 103 #region WebSocket的的四次额外握手信息 104 /// <summary> 105 /// 打包握手信息 106 /// </summary> 107 /// <param name="secKeyAccept"></param> 108 /// <returns></returns> 109 private static byte[] PackHandShakeData(string secKeyAccept) 110 { 111 var responseBuilder = new StringBuilder(); 112 responseBuilder.Append("HTTP/1.1 101 Switching Protocols" + Environment.NewLine); 113 responseBuilder.Append("Upgrade: websocket" + Environment.NewLine); 114 responseBuilder.Append("Connection: Upgrade" + Environment.NewLine); 115 responseBuilder.Append("Sec-WebSocket-Accept: " + secKeyAccept + Environment.NewLine + Environment.NewLine); 116 return Encoding.UTF8.GetBytes(responseBuilder.ToString()); 117 } 118 /// <summary> 119 /// 生成Sec-WebSocket-Accept 120 /// </summary> 121 /// <param name="handShakeText">客户端握手信息</param> 122 /// <returns>Sec-WebSocket-Accept</returns> 123 private static string GetSecKeyAccetp(byte[] handShakeBytes, int bytesLength) 124 { 125 string handShakeText = Encoding.UTF8.GetString(handShakeBytes, 0, bytesLength); 126 string key = string.Empty; 127 Regex r = new Regex(@"Sec\-WebSocket\-Key:(.*?)\r\n"); 128 Match m = r.Match(handShakeText); 129 if (m.Groups.Count != 0) 130 { 131 key = Regex.Replace(m.Value, @"Sec\-WebSocket\-Key:(.*?)\r\n", "$1").Trim(); 132 } 133 byte[] encryptionString = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11")); 134 return Convert.ToBase64String(encryptionString); 135 } 136 #endregion 137 #region 解析客户端数据 138 /// <summary> 139 /// 解析客户端数据包 140 /// </summary> 141 /// <param name="recBytes">服务器接收的数据包</param> 142 /// <param name="recByteLength">有效数据长度</param> 143 /// <returns></returns> 144 private string AnalyticData(byte[] recBytes, int recByteLength) 145 { 146 if (recByteLength < 2) { return string.Empty; } 147 bool fin = (recBytes[0] & 0x80) == 0x80; // 1bit,1表示最后一帧 148 if (!fin) 149 { 150 return string.Empty;// 超过一帧暂不处理 151 } 152 bool mask_flag = (recBytes[1] & 0x80) == 0x80; // 是否包含掩码 153 if (!mask_flag) 154 { 155 return string.Empty;// 不包含掩码的暂不处理 156 } 157 int payload_len = recBytes[1] & 0x7F; // 数据长度 158 byte[] masks = new byte[4]; 159 byte[] payload_data; 160 if (payload_len == 126) 161 { 162 Array.Copy(recBytes, 4, masks, 0, 4); 163 payload_len = (UInt16)(recBytes[2] << 8 | recBytes[3]); 164 payload_data = new byte[payload_len]; 165 Array.Copy(recBytes, 8, payload_data, 0, payload_len); 166 } 167 else if (payload_len == 127) 168 { 169 Array.Copy(recBytes, 10, masks, 0, 4); 170 byte[] uInt64Bytes = new byte[8]; 171 for (int i = 0; i < 8; i++) 172 { 173 uInt64Bytes[i] = recBytes[9 - i]; 174 } 175 UInt64 len = BitConverter.ToUInt64(uInt64Bytes, 0); 176 payload_data = new byte[len]; 177 for (UInt64 i = 0; i < len; i++) 178 { 179 payload_data[i] = recBytes[i + 14]; 180 } 181 } 182 else 183 { 184 Array.Copy(recBytes, 2, masks, 0, 4); 185 payload_data = new byte[payload_len]; 186 Array.Copy(recBytes, 6, payload_data, 0, payload_len); 187 } 188 for (var i = 0; i < payload_len; i++) 189 { 190 payload_data[i] = (byte)(payload_data[i] ^ masks[i % 4]); 191 } 192 return Encoding.UTF8.GetString(payload_data); 193 } 194 #endregion 195 #region 打包要发送的数据 196 /// <summary> 197 /// 打包服务器数据 198 /// </summary> 199 /// <param name="message">需要打包的数据(通讯用)</param> 200 /// <returns>数据包</returns> 201 private byte[] PackData(byte[] message) 202 { 203 byte[] contentBytes = null; 204 if (message.Length < 126) 205 { 206 contentBytes = new byte[message.Length + 2]; 207 contentBytes[0] = 0x81; 208 contentBytes[1] = (byte)message.Length; 209 Array.Copy(message, 0, contentBytes, 2, message.Length); 210 } 211 else if (message.Length < 0xFFFF) 212 { 213 contentBytes = new byte[message.Length + 4]; 214 contentBytes[0] = 0x81; 215 contentBytes[1] = 126; 216 217 218 contentBytes[2] = (byte)(message.Length & 0xFF); 219 contentBytes[3] = (byte)(message.Length >> 8 & 0xFF); 220 Array.Copy(message, 0, contentBytes, 4, message.Length); 221 } 222 else 223 { 224 contentBytes = new byte[message.Length + 10]; 225 contentBytes[0] = 0x81; 226 contentBytes[1] = 127; 227 byte[] ulonglen = BitConverter.GetBytes((long)message.Length); 228 contentBytes[2] = ulonglen[7]; 229 contentBytes[3] = ulonglen[6]; 230 contentBytes[4] = ulonglen[5]; 231 contentBytes[5] = ulonglen[4]; 232 contentBytes[6] = ulonglen[3]; 233 contentBytes[7] = ulonglen[2]; 234 contentBytes[8] = ulonglen[1]; 235 contentBytes[9] = ulonglen[0]; 236 Array.Copy(message, 0, contentBytes, 10, message.Length); 237 } 238 return contentBytes; 239 } 240 #endregion 241 242 } 243 /// <summary> 244 /// Socket回调类型 245 /// </summary> 246 public enum Socket_CallBack_Type : uint 247 { 248 [Description("连接成功")] 249 connect_succ = 0, 250 [Description("连接失败")] 251 connect_fail = 1, 252 [Description("接收返回")] 253 receive = 2, 254 [Description("发送返回")] 255 send = 3, 256 [Description("客户端被迫断开")] 257 client_passive_off = 4, 258 [Description("客户端主动断开")] 259 client_active_off = 5 260 } 261 }View Code
3、在winform主窗口上添加一个按钮,修改代码:
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.Tasks; 11 using System.Windows.Forms; 12 13 namespace WSWin 14 { 15 public partial class Form1 : Form 16 { 17 static WebSocket_Service webSocket_Service; 18 static Socket _socket; 19 public Form1() 20 { 21 InitializeComponent(); 22 } 23 24 private void Form1_Load(object sender, EventArgs e) 25 { 26 IPEndPoint ip_port = new IPEndPoint(IPAddress.Any, 16060); 27 28 webSocket_Service = new WebSocket_Service(ip_port, callback); 29 webSocket_Service.Start(); 30 } 31 32 private void callback(Socket_CallBack_Type socket_CallBack_Type, Object obj, Socket socket) 33 { 34 _socket = socket; 35 webSocket_Service.Send2Msg(_socket, "11111111"); 36 } 37 38 private void button1_Click(object sender, EventArgs e) 39 { 40 if (null != _socket) 41 webSocket_Service.Send2Msg(_socket, "22222"); 42 } 43 } 44 }View Code
4、创建一个客户端网页
1 <!DOCTYPE html> 2 3 <html lang="en" xmlns="http://www.w3.org/1999/xhtml"> 4 <head> 5 <meta charset="utf-8" /> 6 <title>websockets</title> 7 </head> 8 <body> 9 <button id="start">click to start</button> 10 <div id="messages"></div> 11 12 <script type="text/javascript"> 13 var button = document.getElementById("start"); 14 button.onclick = function () { 15 onconnect(); 16 } 17 18 function onconnect() { 19 var websocketAddr = "ws://192.168.3.179:16060/"; 20 var webSocket = new WebSocket(websocketAddr); 21 webSocket.onopen = function (event) { 22 document.getElementById('messages').innerHTML 23 = '消息通道开启,可以发送消息了'; 24 webSocket.send('Hello , I am Egret Test By Aonaufly'); 25 }; 26 webSocket.onmessage = function (event) { 27 document.getElementById('messages').innerHTML 28 += '<br />来自服务器的消息' + event.data; 29 }; 30 webSocket.onerror = function (event) { 31 alert("链接失败"); 32 }; 33 webSocket.onclose = function (event) { 34 alert("链接已断开"); 35 36 setTimeout(function () { 37 onconnect() 38 }, 5 * 1000); 39 } 40 } 41 </script> 42 </body> 43 44 </html>View Code
5、启动winform程序、客户端页面点击click to start
6、点击winform程序的上button按钮,实现通讯
标签:contentBytes,websocket,C#,System,using,byte,message,服务端,客户端 From: https://www.cnblogs.com/handsomeziff/p/17970052