服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C# - C#基于WebSocket实现聊天室功能

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

2022-12-26 14:14Sean包子哥 C#

这篇文章主要为大家详细介绍了C#基于WebSocket实现聊天室功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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

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

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

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

ServerHelper:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<!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>

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

原文链接:https://blog.csdn.net/liuhelong/article/details/8789392

延伸 · 阅读

精彩推荐
  • C#Unity实现通用的信息提示框

    Unity实现通用的信息提示框

    这篇文章主要为大家详细介绍了Unity实现通用的信息提示框,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    xiaochenXIHUA5432022-09-16
  • C#90分钟实现一门编程语言(极简解释器教程)

    90分钟实现一门编程语言(极简解释器教程)

    本文介绍了如何使用 C# 实现一个简化 Scheme——iScheme 及其解释器,需要的朋友可以参考下...

    C#教程网7782021-12-11
  • C#unity实现虚拟摇杆控制Virtual Joystick

    unity实现虚拟摇杆控制Virtual Joystick

    这篇文章主要为大家详细介绍了unity实现虚拟摇杆控制Virtual Joystick,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    代码黑洞_9952022-09-01
  • C#详解C#中一维数组的插入

    详解C#中一维数组的插入

    本文内容给大家分享了在C#中进行一维数组的插入的详细实例代码,大家可以测试下。...

    彬菌6052022-02-21
  • C#深入理解C#窗体关闭事件

    深入理解C#窗体关闭事件

    很多初学者都想把默认的C#关闭按钮事件弄明白,本文就介绍一下C#窗体关闭事件,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙...

    星星是我9552022-12-07
  • C#C#中backgroundworker的使用教程

    C#中backgroundworker的使用教程

    这篇文章主要介绍了C#中backgroundworker的使用教程,在文中有两点需要注意的,大家可以看下...

    秋漓10172022-02-23
  • C#解析C#设计模式编程中外观模式Facade Pattern的应用

    解析C#设计模式编程中外观模式Facade Pattern的应用

    这篇文章主要介绍了C#设计模式编程中外观模式Facade Pattern的应用,外观模式中分为门面(Facade)和子系统(subsystem)两个角色来进行实现,需要的朋友可以参...

    田志良6082021-11-12
  • C#C# 中如何取绝对值函数

    C# 中如何取绝对值函数

    本文主要介绍了C# 中取绝对值的函数。具有很好的参考价值。下面跟着小编一起来看下吧...

    LJD泊水5002021-12-29