<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文範例為大家分享了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[] { "rn" }, 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 Handshakern"); header.AppendFormat("Upgrade: {0}rn", table.ContainsKey("Upgrade") ? table["Upgrade"].ToString() : string.Empty); header.AppendFormat("Connection: {0}rn", table.ContainsKey("Connection") ? table["Connection"].ToString() : string.Empty); header.AppendFormat("WebSocket-Origin: {0}rn", table.ContainsKey("Sec-WebSocket-Origin") ? table["Sec-WebSocket-Origin"].ToString() : string.Empty); header.AppendFormat("WebSocket-Location: {0}rn", 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}rn", Convert.ToBase64String(SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(key + magic)))); header.Append("rn"); 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>
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45