欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-03-01 13:29:27
本文实例为大家分享了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>

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