C#基于WebSocket实现聊天室功能
程序员文章站
2022-06-04 07:50:04
本文实例为大家分享了c#基于websocket实现聊天室功能的具体代码,供大家参考,具体内容如下前面两篇温习了,c# socket内容本章根据socket异步聊天室修改成websocket聊天室web...
本文实例为大家分享了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>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: ASP.Net Core MVC基础系列之环境设置
下一篇: python实现爬取图书封面