C#基于WebSocket实现聊天室功能

C#基于WebSocket实现聊天室功能

本文实例为大家分享了C#基于WebSocket实现聊天室功能的具体代码,供大家参考,具体内容如下

前面两篇温习了,C# Socket内容

本章根据Socket异步聊天室修改成WebSocket聊天室

WebSocket特别的地方是 握手和消息内容的编码、解码(添加了ServerHelper协助处理)

ServerHelper:

using System; using System.Collections; using System.Text; using System.Security.Cryptography; namespace SocketDemo {     // Server助手 负责:1 握手 2 请求转换 3 响应转换     class ServerHelper     {         /// <summary>         /// 输出连接头信息         /// </summary>         public static string ResponseHeader(string requestHeader)         {             Hashtable table = new Hashtable();             // 拆分成键值对,保存到哈希表             string[] rows = requestHeader.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries);             foreach (string row in rows)             {                 int splitIndex = row.IndexOf(':');                 if (splitIndex > 0)                 {                     table.Add(row.Substring(0, splitIndex).Trim(), row.Substring(splitIndex + 1).Trim());                 }             }             StringBuilder header = new StringBuilder();             header.Append("HTTP/1.1 101 Web Socket Protocol Handshake\r\n");             header.AppendFormat("Upgrade: {0}\r\n", table.ContainsKey("Upgrade") ? table["Upgrade"].ToString() : string.Empty);             header.AppendFormat("Connection: {0}\r\n", table.ContainsKey("Connection") ? table["Connection"].ToString() : string.Empty);             header.AppendFormat("WebSocket-Origin: {0}\r\n", table.ContainsKey("Sec-WebSocket-Origin") ? table["Sec-WebSocket-Origin"].ToString() : string.Empty);             header.AppendFormat("WebSocket-Location: {0}\r\n", table.ContainsKey("Host") ? table["Host"].ToString() : string.Empty);             string key = table.ContainsKey("Sec-WebSocket-Key") ? table["Sec-WebSocket-Key"].ToString() : string.Empty;             string magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";             header.AppendFormat("Sec-WebSocket-Accept: {0}\r\n", Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + magic))));             header.Append("\r\n");             return header.ToString();         }         /// <summary>         /// 解码请求内容         /// </summary>         public static string DecodeMsg(Byte[] buffer, int len)         {             if (buffer[0] != 0x81                 || (buffer[0] & 0x80) != 0x80                 || (buffer[1] & 0x80) != 0x80)             {                 return null;             }             Byte[] mask = new Byte[4];             int beginIndex = 0;             int payload_len = buffer[1] & 0x7F;             if (payload_len == 0x7E)             {                 Array.Copy(buffer, 4, mask, 0, 4);                 payload_len = payload_len & 0x00000000;                 payload_len = payload_len | buffer[2];                 payload_len = (payload_len << 8) | buffer[3];                 beginIndex = 8;             }             else if (payload_len != 0x7F)             {                 Array.Copy(buffer, 2, mask, 0, 4);                 beginIndex = 6;             }             for (int i = 0; i < payload_len; i++)             {                 buffer[i + beginIndex] = (byte)(buffer[i + beginIndex] ^ mask[i % 4]);             }             return Encoding.UTF8.GetString(buffer, beginIndex, payload_len);         }         /// <summary>         /// 编码响应内容         /// </summary>         public static byte[] EncodeMsg(string content)         {             byte[] bts = null;             byte[] temp = Encoding.UTF8.GetBytes(content);             if (temp.Length < 126)             {                 bts = new byte[temp.Length + 2];                 bts[0] = 0x81;                 bts[1] = (byte)temp.Length;                 Array.Copy(temp, 0, bts, 2, temp.Length);             }             else if (temp.Length < 0xFFFF)             {                 bts = new byte[temp.Length + 4];                 bts[0] = 0x81;                 bts[1] = 126;                 bts[2] = (byte)(temp.Length & 0xFF);                 bts[3] = (byte)(temp.Length >> 8 & 0xFF);                 Array.Copy(temp, 0, bts, 4, temp.Length);             }             else             {                 byte[] st = System.Text.Encoding.UTF8.GetBytes(string.Format("暂不处理超长内容").ToCharArray());             }             return bts;         }     } }

Server:

using System; using System.Collections.Generic; using System.Text; using System.Net; using System.Net.Sockets; namespace SocketDemo {     class ClientInfo     {         public Socket Socket { get; set; }         public bool IsOpen { get; set; }         public string Address { get; set; }     }     // 管理Client     class ClientManager     {         static List<ClientInfo> clientList = new List<ClientInfo>();         public static void Add(ClientInfo info)         {             if (!IsExist(info.Address))             {                 clientList.Add(info);             }         }         public static bool IsExist(string address)         {             return clientList.Exists(item => string.Compare(address, item.Address, true) == 0);         }         public static bool IsExist(string address, bool isOpen)         {             return clientList.Exists(item => string.Compare(address, item.Address, true) == 0 && item.IsOpen == isOpen);         }         public static void Open(string address)         {             clientList.ForEach(item =>             {                 if (string.Compare(address, item.Address, true) == 0)                 {                     item.IsOpen = true;                 }             });         }         public static void Close(string address = null)         {             clientList.ForEach(item =>             {                 if (address == null || string.Compare(address, item.Address, true) == 0)                 {                     item.IsOpen = false;                     item.Socket.Shutdown(SocketShutdown.Both);                 }             });         }         // 发送消息到ClientList         public static void SendMsgToClientList(string msg, string address = null)         {             clientList.ForEach(item =>             {                 if (item.IsOpen && (address == null || item.Address != address))                 {                     SendMsgToClient(item.Socket, msg);                 }             });         }         public static void SendMsgToClient(Socket client, string msg)         {             byte[] bt = ServerHelper.EncodeMsg(msg);             client.BeginSend(bt, 0, bt.Length, SocketFlags.None, new AsyncCallback(SendTarget), client);         }         private static void SendTarget(IAsyncResult res)         {             //Socket client = (Socket)res.AsyncState;             //int size = client.EndSend(res);         }     }     // 接收消息     class ReceiveHelper     {         public byte[] Bytes { get; set; }         public void ReceiveTarget(IAsyncResult res)         {             Socket client = (Socket)res.AsyncState;             int size = client.EndReceive(res);             if (size > 0)             {                 string address = client.RemoteEndPoint.ToString(); // 获取Client的IP和端口                 string stringdata = null;                 if (ClientManager.IsExist(address, false)) // 握手                 {                     stringdata = Encoding.UTF8.GetString(Bytes, 0, size);                     ClientManager.SendMsgToClient(client, ServerHelper.ResponseHeader(stringdata));                     ClientManager.Open(address);                 }                 else                 {                     stringdata = ServerHelper.DecodeMsg(Bytes, size);                 }                 if (stringdata.IndexOf("exit") > -1)                 {                     ClientManager.SendMsgToClientList(address + "已从服务器断开", address);                     ClientManager.Close(address);                     Console.WriteLine(address + "已从服务器断开");                     Console.WriteLine(address + " " + DateTimeOffset.Now.ToString("G"));                     return;                 }                 else                 {                     Console.WriteLine(stringdata);                     Console.WriteLine(address + " " + DateTimeOffset.Now.ToString("G"));                     ClientManager.SendMsgToClientList(stringdata, address);                 }             }             // 继续等待             client.BeginReceive(Bytes, 0, Bytes.Length, SocketFlags.None, new AsyncCallback(ReceiveTarget), client);         }     }     // 监听请求     class AcceptHelper     {         public byte[] Bytes { get; set; }         public void AcceptTarget(IAsyncResult res)         {             Socket server = (Socket)res.AsyncState;             Socket client = server.EndAccept(res);             string address = client.RemoteEndPoint.ToString();             ClientManager.Add(new ClientInfo() { Socket = client, Address = address, IsOpen = false });             ReceiveHelper rs = new ReceiveHelper() { Bytes = this.Bytes };             IAsyncResult recres = client.BeginReceive(rs.Bytes, 0, rs.Bytes.Length, SocketFlags.None, new AsyncCallback(rs.ReceiveTarget), client);             // 继续监听             server.BeginAccept(new AsyncCallback(AcceptTarget), server);         }     }     class Program     {         static void Main(string[] args)         {             Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);             server.Bind(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 200)); // 绑定IP+端口             server.Listen(10); // 开始监听             Console.WriteLine("等待连接...");             AcceptHelper ca = new AcceptHelper() { Bytes = new byte[2048] };             IAsyncResult res = server.BeginAccept(new AsyncCallback(ca.AcceptTarget), server);             string str = string.Empty;             while (str != "exit")             {                 str = Console.ReadLine();                 Console.WriteLine("ME: " + DateTimeOffset.Now.ToString("G"));                 ClientManager.SendMsgToClientList(str);             }             ClientManager.Close();             server.Close();         }     } }

Client:

<!DOCTYPE html> <script>     var mySocket;     function Star() {         mySocket = new WebSocket("ws://127.0.0.1:200", "my-custom-protocol");         mySocket.onopen = function Open() {             Show("连接打开");         };         mySocket.onmessage = function (evt) {             Show(evt.data);         };         mySocket.onclose = function Close() {             Show("连接关闭");             mySocket.close();         };     }     function Send() {         var content = document.getElementById("content").value;         Show(content);         mySocket.send(content);     }     function Show(msg) {         var roomContent = document.getElementById("roomContent");         roomContent.innerHTML = msg + "<br/>" + roomContent.innerHTML;     } </script> <html> <head>     <title></title> </head> <body>     <div id="roomContent" style="width: 500px; height: 200px; overflow: hidden; border: 2px solid #686868;         margin-bottom: 10px; padding: 10px 0px 0px 10px;">     </div>     <div>         <textarea id="content" cols="50" rows="3" style="padding: 10px 0px 0px 10px;"></textarea>     </div>     <input type="button" value="Connection" οnclick="Star()" />     <input type="button" value="Send" οnclick="Send()" /> </body> </html>

推荐阅读