本文实例为大家分享了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