好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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>

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

查看更多关于C#基于WebSocket实现聊天室功能的详细内容...

  阅读:51次