C# 使用 ClientWebSocket 實現 WebSocket 客戶端
C# Net Core 使用 ClientWebSocket 實現 WebSocket 客戶端
Net Core 使用 ClientWebSocket 實現 WebSocket 客戶端
我們模仿HTML5的實現方式來重寫一個C#類
https://www.runoob.com/html/html5-websocket.html
WebSocket 屬性
HTML5 | 描述 | NET Core | 描述 |
readyState | 只讀屬性 readyState 表示連接狀態,可以是以下值: 0 - 表示連接尚未建立。 1 - 表示連接已建立,可以進行通信。 2 - 表示連接正在進行關閉。 3 - 表示連接已經關閉或者連接不能打開。 |
State | WebSocket狀態(點擊看官方文檔) |
bufferedAmount | 只讀屬性 bufferedAmount 已被 send() 放入正在隊列中等待傳輸,但是還沒有發出的 UTF-8 文本字節數。 | ------ | 無此屬性 |
WebSocket 事件
HTML5 | 描述 | NET Core | 描述 |
onopen | 連接建立時觸發 | OnOpen | 連接建立時觸發 |
onmessage | 客戶端接收服務端數據時觸發 | OnMessage | 客戶端接收服務端數據時觸發(暫時只支持文本消息) |
onerror | 通信發生錯誤時觸發 | OnError | 通信發生錯誤時觸發 (如果處理消息中有錯誤事件沒有處理,這里也會拋出並斷開鏈接) |
onclose | 連接關閉時觸發 | OnClose | 連接關閉時觸發 |
WebSocket 方法
HTML5 | 描述 | NET Core | 描述 |
send() | 使用連接發送數據 | bool Send(string mess) bool Send(byte[] bytes) |
使用連接發送文本消息 返回:是否嘗試了發送 |
close() | 關閉連接 | void Close() void Close(WebSocketCloseStatus closeStatus, string statusDescription) |
關閉連接(關閉原因為用戶手動關閉) 關閉連接(自定義關閉原因) |
代碼如下:
創建文件WSocketClientHelp.cs:
復制如下代碼進去
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Net.WebSockets;
using
System.Text;
using
System.Threading;
using
System.Threading.Tasks;
namespace
YingCaiEdu.Common.HttpHelp
{
public
class
WSocketClientHelp
{
ClientWebSocket ws =
null
;
Uri uri =
null
;
bool
isUserClose =
false
;
//是否最后由用戶手動關閉
/// <summary>
/// WebSocket狀態
/// </summary>
public
WebSocketState? State {
get
=> ws?.State; }
/// <summary>
/// 包含一個數據的事件
/// </summary>
public
delegate
void
MessageEventHandler(
object
sender,
string
data);
public
delegate
void
ErrorEventHandler(
object
sender, Exception ex);
/// <summary>
/// 連接建立時觸發
/// </summary>
public
event
EventHandler OnOpen;
/// <summary>
/// 客戶端接收服務端數據時觸發
/// </summary>
public
event
MessageEventHandler OnMessage;
/// <summary>
/// 通信發生錯誤時觸發
/// </summary>
public
event
ErrorEventHandler OnError;
/// <summary>
/// 連接關閉時觸發
/// </summary>
public
event
EventHandler OnClose;
public
WSocketClientHelp(
string
wsUrl)
{
uri =
new
Uri(wsUrl);
ws =
new
ClientWebSocket();
}
/// <summary>
/// 打開鏈接
/// </summary>
public
void
Open()
{
Task.Run(async () =>
{
if
(ws.State == WebSocketState.Connecting || ws.State == WebSocketState.Open)
return
;
string
netErr =
string
.Empty;
try
{
//初始化鏈接
isUserClose =
false
;
ws =
new
ClientWebSocket();
await ws.ConnectAsync(uri, CancellationToken.None);
if
(OnOpen !=
null
)
OnOpen(ws,
new
EventArgs());
Send(
"放映"
);
//全部消息容器
List<
byte
> bs =
new
List<
byte
>();
//緩沖區
var
buffer =
new
byte
[1024 * 4];
//監聽Socket信息
WebSocketReceiveResult result = await ws.ReceiveAsync(
new
ArraySegment<
byte
>(buffer), CancellationToken.None);
//是否關閉
while
(!result.CloseStatus.HasValue)
{
//文本消息
if
(result.MessageType == WebSocketMessageType.Text)
{
bs.AddRange(buffer.Take(result.Count));
//消息是否已接收完全
if
(result.EndOfMessage)
{
//發送過來的消息
string
userMsg = Encoding.UTF8.GetString(bs.ToArray(), 0, bs.Count);
if
(OnMessage !=
null
)
OnMessage(ws, userMsg);
//清空消息容器
bs =
new
List<
byte
>();
}
}
//繼續監聽Socket信息
result = await ws.ReceiveAsync(
new
ArraySegment<
byte
>(buffer), CancellationToken.None);
}
////關閉WebSocket(服務端發起)
//await ws.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
}
catch
(Exception ex)
{
netErr =
" .Net發生錯誤"
+ ex.Message;
if
(OnError !=
null
)
OnError(ws, ex);
//if (ws != null && ws.State == WebSocketState.Open)
// //關閉WebSocket(客戶端發起)
// await ws.CloseAsync(WebSocketCloseStatus.Empty, ex.Message, CancellationToken.None);
}
finally
{
if
(!isUserClose)
Close(ws.CloseStatus.Value, ws.CloseStatusDescription + netErr);
}
});
}
/// <summary>
/// 使用連接發送文本消息
/// </summary>
/// <param name="ws"></param>
/// <param name="mess"></param>
/// <returns>是否嘗試了發送</returns>
public
bool
Send(
string
mess)
{
if
(ws.State != WebSocketState.Open)
return
false
;
Task.Run(async () =>
{
var
replyMess = Encoding.UTF8.GetBytes(mess);
//發送消息
await ws.SendAsync(
new
ArraySegment<
byte
>(replyMess), WebSocketMessageType.Text,
true
, CancellationToken.None);
});
return
true
;
}
/// <summary>
/// 使用連接發送字節消息
/// </summary>
/// <param name="ws"></param>
/// <param name="mess"></param>
/// <returns>是否嘗試了發送</returns>
public
bool
Send(
byte
[] bytes)
{
if
(ws.State != WebSocketState.Open)
return
false
;
Task.Run(async () =>
{
//發送消息
await ws.SendAsync(
new
ArraySegment<
byte
>(bytes), WebSocketMessageType.Binary,
true
, CancellationToken.None);
});
return
true
;
}
/// <summary>
/// 關閉連接
/// </summary>
public
void
Close()
{
isUserClose =
true
;
Close(WebSocketCloseStatus.NormalClosure,
"用戶手動關閉"
);
}
public
void
Close(WebSocketCloseStatus closeStatus,
string
statusDescription)
{
Task.Run(async () =>
{
try
{
//關閉WebSocket(客戶端發起)
await ws.CloseAsync(closeStatus, statusDescription, CancellationToken.None);
}
catch
(Exception ex)
{
}
ws.Abort();
ws.Dispose();
if
(OnClose !=
null
)
OnClose(ws,
new
EventArgs());
});
}
}
}
|
使用方法:
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
|
using
System;
using
System.Collections.Generic;
using
System.Linq;
using
System.Net.WebSockets;
using
System.Text;
using
System.Threading;
using
System.Threading.Tasks;
using
YingCaiEdu.Common.HttpHelp;
namespace
YingCaiEdu.PPT.VstoPpt
{
public
class
PptSocket
{
private
static
PptSocket _this;
public
static
PptSocket This
{
get
{
if
(_this ==
null
)
{
_this =
new
PptSocket();
}
return
_this;
}
}
public
WSocketClientHelp wSocketClient =
new
WSocketClientHelp(
"wss://baidu.com?user=ppt"
);
public
void
Go()
{
wSocketClient.OnOpen -= WSocketClient_OnOpen;
wSocketClient.OnMessage -= WSocketClient_OnMessage;
wSocketClient.OnClose -= WSocketClient_OnClose;
wSocketClient.OnError -= WSocketClient_OnError;
wSocketClient.OnOpen += WSocketClient_OnOpen;
wSocketClient.OnMessage += WSocketClient_OnMessage;
wSocketClient.OnClose += WSocketClient_OnClose;
wSocketClient.OnError += WSocketClient_OnError;
wSocketClient.Open();
}
private
void
WSocketClient_OnError(
object
sender, Exception ex)
{
}
private
void
WSocketClient_OnClose(
object
sender, EventArgs e)
{
}
private
void
WSocketClient_OnMessage(
object
sender,
string
data)
{
//處理的消息錯誤將會忽略
try
{
if
(data.Contains(
"放映"
))
{
PptVstoApp.GetPptApp.SlideShowFromCurrent();
}
}
catch
(Exception ex)
{
}
}
private
void
WSocketClient_OnOpen(
object
sender, EventArgs e)
{
}
}
}
|
完成
轉自:https://www.cnblogs.com/ping9719/p/14821508.html