|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 ( G5 A$ O2 t% m2 b! y
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
3 ^6 G2 _6 [/ X0 U( s) A - using System.Collections.Generic;& z: V) c. d: ^9 y8 B% O
- using System.Linq;
& T s0 V- c4 ?' `- K - using System.Net.WebSockets;
, g4 {& b3 C1 v: R4 J+ J% K; s - using System.Text;
1 J8 r4 j. [: }2 f - using System.Threading;
, d9 Y% o: _( N' v8 K, c7 } - using System.Threading.Tasks;# T! h4 D f9 l8 f6 e- F% g; j
- using System.Web;# ^6 U8 W5 N; ]" o8 e8 _
- using System.Web.WebSockets;
7 q( y& i7 k) d9 o, ^* C9 _
/ k; j* A) y5 O8 d; `- + q5 `' I& w8 C+ u
- namespace WebApplicationWebsocketHandler" R) c) u2 B' b3 f) {% ?# L N2 @! f N
- {
u$ x! b* G7 ^* t; l - /// <summary>/ c W1 e6 m8 d- L/ Z
- /// 离线消息: c/ s) h9 \; y; B- F4 Y, D8 [# Q
- /// </summary>$ o0 a8 @3 C# O, @0 e# Z% G1 S, O
- public class MessageInfo
l9 M0 P2 d# B* W7 z, u; d, B& R/ ^ - {
. c1 T7 t; F7 ] - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
9 l4 U9 w: J* {5 o7 z - {
3 C+ l6 {9 L, |) R. J - MsgTime = _MsgTime;) k; |+ c( y# W
- MsgContent = _MsgContent;2 A' S! S' j) S8 o0 A- M
- }
( R, M; ~* V: G; @4 a5 ~8 B. U3 s! w - public DateTime MsgTime { get; set; }) A9 j4 }! D8 d) N% C, h
- public ArraySegment<byte> MsgContent { get; set; }8 T' G2 g% E: ~
- }2 D. R) I2 _5 q! \/ a/ s+ i6 y
4 G2 ]# J: ~! k2 y* Q- 7 m8 r# L N! I
- 0 {! a1 T' y w0 W1 C( x) ], q
- & h& Q# m# i. X' j& f- g" x3 [( U
- /// <summary>
9 U8 X5 ?! i- K3 o* l. V0 x - /// Handler1 的摘要说明0 B+ P, c7 y( k& t& H$ g
- /// </summary>
6 `! u. A; J9 [! Y; t - public class Handler1 : IHttpHandler' Z: U. Z4 E8 N% s6 s
- {
7 c& M- ~+ R, V2 m! Y1 p8 `& [9 Y - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
& q/ j3 D2 P8 {( {/ ^; P, y - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池# H$ p9 q% ?/ M. K5 z) ^
- public void ProcessRequest(HttpContext context)
2 |! {; Z, J4 l9 b- a b( @ - {
% x8 |3 k9 T; m+ t& [$ ? - //context.Response.ContentType = "text/plain";
0 K% R8 m4 L, m2 u2 U) v, E7 Y - //context.Response.Write("Hello World");& ~. h, O5 r: I4 E/ x3 I: J: @- I
- if (context.IsWebSocketRequest)
`5 B( v& O! Q" s! r5 M( |. p6 S! F - {" ?) R- `* Q5 s' h
- context.AcceptWebSocketRequest(ProcessChat);
- s' u& Q$ i- c2 f) y2 N$ P - }
5 K) y1 O8 U% G, H* h$ a - }& h/ W$ N0 E8 C G+ e
+ Q D! f8 o) v" ]* o" G" a- private async Task ProcessChat(AspNetWebSocketContext context)& t7 e0 r" Z/ H+ v8 `
- {5 ^' S8 l+ c. C0 J1 N
- WebSocket socket = context.WebSocket;3 \$ b$ W1 I& f8 I0 l T
- string user = context.QueryString["user"].ToString();. p; L2 Y+ _! ~( i% B
- " s. f+ Q7 a. m. ?
- try% q2 Z- _/ M% y u7 K3 Y
- {
2 B! Z7 Q/ Q% B' m9 V a - #region 用户添加连接池
, y8 [. P! W3 a4 j' O - //第一次open时,添加到连接池中' Y: I$ l0 M( R& k N6 \$ J8 I
- if (!CONNECT_POOL.ContainsKey(user)) g4 r' _% N r
- CONNECT_POOL.Add(user, socket);//不存在,添加
0 l8 G* b) }9 T - else
4 X/ h5 D1 N# i* J3 F7 a0 `; q - if (socket != CONNECT_POOL[user])//当前对象不一致,更新: ~" g( m$ Q8 j+ n4 E2 i2 [& y3 G) H
- CONNECT_POOL[user] = socket;
" e" x7 f, q( d6 B( Q) b6 f' A$ g - #endregion
# j$ G/ S6 \! {8 n2 `: S8 _ - ! a! C* r. H* I; `
- #region 离线消息处理
5 n( ^. s ] K' r - if (MESSAGE_POOL.ContainsKey(user)); W* i6 H2 Z) b0 m
- {
7 W3 ?. Q" n- O0 m* d. R) x, x p1 _ - List<MessageInfo> msgs = MESSAGE_POOL[user];8 M. ~6 X% s1 Y1 U
- foreach (MessageInfo item in msgs)
P$ V# }6 K0 A0 m( X5 v - {* D7 D3 u1 K u b
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);; G, ~4 B) d& c* S$ m
- }0 i, L8 M; G* A& W
- MESSAGE_POOL.Remove(user);//移除离线消息
3 K7 k h8 U1 d6 g( G) i - }) o, Z' S4 l# ?7 ^$ C8 b2 o3 [
- #endregion! e9 I4 Q9 F+ Z. R9 A: j
- $ {" e) {7 u) s
- string descUser = string.Empty;//目的用户
8 I1 A1 b" w$ I% F1 e. k* k - while (true)8 y5 G/ n: G2 @' t. X% z3 `2 ?/ `
- {
8 z. q& P$ K) n( u9 o; ?& t$ c) w - if (socket.State == WebSocketState.Open)* H& }5 ^ H7 y: T; `
- {
$ ~4 U# L1 H* L - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);: ^7 L) U( W+ I' m& L) |. i! N( e4 k
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);* V: r' G D% q
- 7 t& _$ z6 C0 j5 C: s3 {( a, b
- #region 消息处理(字符截取、消息转发)$ D, Q: \, p# `: e. x) X0 c
- try
- W! o& e- [/ _# ]7 V - {
4 l" X4 ]2 p% c$ F# f* c% Y4 U - #region 关闭Socket处理,删除连接池
, X: s/ H% g1 c6 t - if (socket.State != WebSocketState.Open)//连接关闭) @& O2 u& Z2 K9 E. ]% l8 q
- {* d; C2 h; y4 d# E: V1 G
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池" X6 v7 m8 c; `" N/ }4 @+ a
- break;" }: M) V6 C1 k7 C/ ?1 ?; G% L% {
- }
' O- ~4 `/ v c D1 R5 Y - #endregion% t2 G/ M- n! {! }! g- j& P
- # t/ p% F8 o# R/ W1 O& B
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息7 ]/ f4 n# F6 }) j8 X
- string[] msgList = userMsg.Split('|');8 E9 u8 T: H) c" }
- if (msgList.Length == 2)
/ t3 n5 r, J) g - {, s% w2 H6 ^: H7 j4 Q9 l
- if (msgList[0].Trim().Length > 0)% F( w( f6 P! O
- descUser = msgList[0].Trim();//记录消息目的用户. s0 g9 S# J! t1 F1 r/ K# F0 R6 q8 ~
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));5 \* ]; N5 O) L4 v9 `6 q/ B- V
- }( l; n* T* l4 _
- else& z$ Q& M G, y# s7 {$ U
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
4 Q7 s& B9 G! ?' L0 [ - % G* X, i3 P3 ?: v$ w
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
4 L/ O0 J$ [ G; F, K - {# O% k1 I( V, E
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
2 T: J* P! {9 Y! J F: M, S% z8 s - if (destSocket != null && destSocket.State == WebSocketState.Open)
9 p" B# u1 x9 @7 A4 U1 L - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);- D3 q" G1 @4 m$ _* i0 p* r
- }
5 R) B( _( O9 H4 D/ y; P - else& ?& X. G- g1 ] @, \# L+ B, O
- {
3 @ D X" l; }& {" j% N - Task.Run(() =>. q+ l0 C6 G7 j0 n* x
- {
* ], ?% |' p5 ]* [, v8 R - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
& C. L8 g; ^9 \+ ] - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
0 J- i* _4 [6 O' @7 s s# n - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
$ U+ L, L! n$ U - });: I7 P9 s% c, e# V+ X8 ~6 p2 Q( A
- }* C: T" t B, [* `& x' q
- }
2 b1 {6 h. Q/ H! e3 s9 [4 O& z; @3 E2 q1 { - catch (Exception exs)
( P; q0 l1 M0 F) F' c' `! J - {
3 m5 B6 e z$ t6 o* E+ S) S ` - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
* R& r+ E/ D; r4 v+ D* l4 M: X - }
# n7 _* t/ l0 j8 G: | - #endregion% z( ?! \; l# g9 F% z1 T
- }$ {6 k, J3 |* I b$ ]0 I
- else
% X r4 o: `& c+ J* S - {
0 t8 V) S# ^, ? - break;
& b% q/ c" H1 A" C - }4 ~0 [& |5 J" {+ [! O% q" o; t
- }//while end: A/ A- v' n5 w9 E# p; H* P$ R
- }
6 B W M0 C4 _" E+ |# [, R9 [ v - catch (Exception ex)5 O9 G9 Y; g! k2 H: t; g) i
- {' K/ e% G) g, h$ @
- //整体异常处理' ?) d8 E" ~. q, i( z" m7 d) ]/ m$ g2 n
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
* B7 p1 L. V P1 m! N) a- e - }
) i3 g, ~7 s: H, w - }
2 k [: I+ M; V9 i6 X
* s5 B2 c* Q, R4 e! l; Z5 ? {- i6 D5 G9 y* ]5 E
- public bool IsReusable- o; _3 j* r* B$ S# S
- {: U8 a5 m* ?& i0 y& J4 m2 j! ?
- get: p1 @9 F7 Z& U) @7 A
- {$ Y, ?4 O) B, s5 L& Z/ g F
- return false; v5 |3 q% g5 [
- }
+ ]( ^, i7 b z) z: M - }
: M% Z+ Q) k0 Z3 x - }
$ P' ^$ G/ O; [7 K - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
. I: s4 ?/ r, }/ |% v+ P |