|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
# K. t0 D, k; C) W+ P2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;7 ~, j4 {3 E6 J5 Q& r/ p
- using System.Collections.Generic;% ?2 A. k7 j @1 I, V
- using System.Linq;
0 e2 c9 H0 o0 r, k - using System.Net.WebSockets;# Z+ N# o% h; I7 G+ X& f
- using System.Text;
5 D! {9 b3 u5 B' C5 G6 k - using System.Threading;' I5 V0 J! }6 T. }6 T" a
- using System.Threading.Tasks;! ^+ p8 |3 g! y; {
- using System.Web;7 d3 C1 {3 U1 J9 ]5 j; _% \& W9 p$ I
- using System.Web.WebSockets;3 m) i& J" D. _+ Z" P
- 4 w& o/ ]- H6 m
# i! Y6 M0 U+ f0 x- namespace WebApplicationWebsocketHandler/ N. l% {" T0 S1 z: W; p a
- {
9 |2 C9 G; C. ^. w- w7 w - /// <summary>
# F0 y# P1 l6 e9 @% J \ - /// 离线消息3 |! F8 w- \% j7 C# | Z/ Y- e
- /// </summary>/ u" N$ T- ^( m* j/ I1 ^+ n
- public class MessageInfo
0 h/ ^% V7 E. Z+ k - {
3 t) W" y# j3 L2 O K% Q) n0 ?/ H - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent), f. Q7 i) X1 j' a( a/ O5 f
- {
2 o9 m2 k6 b6 k9 [6 V - MsgTime = _MsgTime;4 n8 |% T$ ?& n1 f4 `8 V C
- MsgContent = _MsgContent;
( |- h; ?. h: M1 t8 M; q- p - }
1 d' j' I8 h# L3 V& `5 V - public DateTime MsgTime { get; set; }
& L- [$ j& _! n2 I% R' p - public ArraySegment<byte> MsgContent { get; set; }
( @- |" e* v; L9 | - }
: t# g: R& D* Q3 T - 1 l1 Z( E3 Y. H* [; Z* k. ~, \% ?
) x8 K2 o( l7 T# R7 f
6 G8 B% i; x! W9 ^- $ G6 ~' c% y1 A2 i
- /// <summary>6 T( N) g! Z, `' [
- /// Handler1 的摘要说明
$ a1 }" Z6 V3 u1 m. t B$ q2 m - /// </summary>% b5 w. a' G# u$ r* o7 I" ]8 G' V
- public class Handler1 : IHttpHandler
+ ~' w8 N- n2 S - {6 j, t, w1 n, W
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池9 ?$ h3 X$ a+ H
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
% E" A6 K# Y! B* T2 c - public void ProcessRequest(HttpContext context)
0 b1 O* T2 t- }3 M' D+ @+ _3 E# P% { - {
# x; g0 |8 J; D' U& D% o - //context.Response.ContentType = "text/plain";
* o* p( g, @( E& u3 T, z - //context.Response.Write("Hello World");6 v- c& b/ `4 L) l1 E. L- L
- if (context.IsWebSocketRequest)
+ {1 q" t3 y& v3 y0 f- y1 n1 R5 ? - {" K' M9 [% o- k1 R
- context.AcceptWebSocketRequest(ProcessChat);
1 w$ X: a; B6 M) B4 a - } 3 r4 j, S& |' t: O Y, N# ~: v
- }
) e/ X2 W, ?! h1 H' p4 ?1 t - * r: }6 Y& d9 a8 l% T4 i
- private async Task ProcessChat(AspNetWebSocketContext context)0 S5 o. ?7 t) k1 W* H% }. D H
- {
; v2 w% a- a |$ S - WebSocket socket = context.WebSocket;4 G" e2 r5 [3 Z# h; C
- string user = context.QueryString["user"].ToString();, A: h9 H# `) Y% r
- 5 w/ a! M- u# }& l' R3 Q
- try
]% O! `1 @$ o - {+ T N0 F4 f. t* C
- #region 用户添加连接池# V& \$ t# ]$ S! w
- //第一次open时,添加到连接池中: l+ A' p2 n8 Z! Z f1 d
- if (!CONNECT_POOL.ContainsKey(user))( T0 ~( |4 z8 b1 C/ X
- CONNECT_POOL.Add(user, socket);//不存在,添加" V* v5 ~+ A9 w! O2 ^9 g; |
- else
, K" a% @# j: B5 }( a - if (socket != CONNECT_POOL[user])//当前对象不一致,更新' B" E, w* H2 v& z
- CONNECT_POOL[user] = socket;
2 V% `5 f, y5 N- ^( i - #endregion
/ d/ v/ t8 X) c. m0 S, C - / v$ ^* k2 B0 U2 Z8 q& U! O6 ?1 \
- #region 离线消息处理
% n" _3 y* Q, f - if (MESSAGE_POOL.ContainsKey(user))
* r: I/ t0 o' U$ e - {2 n0 {9 T1 }2 u
- List<MessageInfo> msgs = MESSAGE_POOL[user]; i" l+ @' I, k+ K) \3 Y7 z: Z
- foreach (MessageInfo item in msgs)
* |2 ^' b7 S; t - {
$ P1 l- q, P$ k - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);5 \4 S( N" F6 h) l$ a9 S
- }% _( i! E* I4 J
- MESSAGE_POOL.Remove(user);//移除离线消息9 G1 i9 G3 O8 P. q* m
- }
2 a! r: P! w4 X; @( j- h! m - #endregion n9 R$ {- }4 Z
. i* B" l$ W+ d9 G& y2 s" B+ `+ i- string descUser = string.Empty;//目的用户& G3 s! r: [' s- e
- while (true)2 ^( u# e1 W+ N
- {
' A5 `1 e1 q% D, a9 C. d" O - if (socket.State == WebSocketState.Open)
/ E8 _; ~( F# H" B1 i) W& I - {
3 `5 a( D* T1 D' T5 f! D - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);5 H& h" `( h2 g) O Y! D9 |
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);% e; p( A2 |/ R& f- U" d! W" ?, b
- / n+ w0 u; O) d3 u+ t9 X; T
- #region 消息处理(字符截取、消息转发)
/ V* k6 h* @+ F2 T - try
3 J' Y% M! c$ l$ R) r9 C: ~ - {
$ A8 W# Q* I! B M% C - #region 关闭Socket处理,删除连接池
7 g1 `5 E2 I; J# ?8 u$ _! n - if (socket.State != WebSocketState.Open)//连接关闭
* V* P: d J' d' x& O - {
7 E8 e# }; R& O( Q' l$ K5 [# E5 Z - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池0 s) p7 K4 G! Z! N3 H
- break;
8 t8 {4 ~0 c/ i- S) _/ f6 d$ g - }3 q/ n4 c- G9 O3 }2 D3 q, p' e
- #endregion8 r- g0 B% `7 d
- , o# D" |$ m- N, B. l4 n
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息- r$ A# O' N: e' \! G6 [
- string[] msgList = userMsg.Split('|');
; o4 j, I" C) q. B' L) q - if (msgList.Length == 2)
4 W2 Z+ Y3 ^- \, } - {
. x/ m2 O0 A) ^0 t - if (msgList[0].Trim().Length > 0)1 j3 o- Q/ _+ p) x; T, Y6 w
- descUser = msgList[0].Trim();//记录消息目的用户
' p! L9 Y5 `/ J) ^ - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
9 \8 F( z9 r) e* U$ |% H t - }
6 o3 ~% w/ y; U1 ^. K - else
I9 k/ w% L) |& J - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));+ Z" T/ R- @- V
- 2 G$ _. P" W s
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线7 Y" [6 c `6 @- T. C
- {2 i! d" x. o& g) e; `* \
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端9 n9 V5 z- N: o& f
- if (destSocket != null && destSocket.State == WebSocketState.Open) j% V7 @' V2 v) e5 L
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
6 B n4 q& N2 j# ~; W$ N - }
. Y3 n" ]" a' K& w' d$ ^3 Z - else
" \( o8 n$ s* ] - {
+ o+ O' J8 ~2 l9 \8 B3 i7 P8 w& y - Task.Run(() =>- q. Y. o! ]/ e8 C! x
- {
5 q' b n q6 f( Y - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
( O1 `2 C, ]0 W+ ]7 j/ P8 Y - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
% A- `, g: X! Z - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
! ]' v" \. N8 V& s$ n - });. r. k: z- l7 ~0 W
- }6 Q& l) s, T W2 [% Y
- }
5 ~: ~8 |, R) Y1 @5 D - catch (Exception exs)2 X, i N7 A! s/ a* G- e
- {9 s) _# H) H: _
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
6 F" |7 s4 ?, _4 \: b' G7 k8 w& v& k - }
/ ~' e" y [: F4 z; h5 } \, b - #endregion2 W! h' O7 g* V! a* P
- }! |$ h5 d8 ?$ d! o0 t1 i Q6 o
- else
* Y4 y3 N" c! p, \& ~; ]. L - {
; ], ?4 ^6 D) [1 d' m - break;
6 ^0 D- C# H0 x3 `* D - }* `( d6 o' B; x6 a3 u0 Q9 X/ C% P
- }//while end0 b0 P0 m1 j0 H
- }
/ V" t& q! Q7 Z8 G" V2 t - catch (Exception ex)
4 G% _2 L. s+ J4 K% Q( ~ - {
V( o# [# f% P2 d9 E2 T* H - //整体异常处理( s- B+ j U! A6 _$ b `
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);4 S9 a2 n5 v$ x# E' D3 `# I
- }) r& T$ F; R1 J G6 g
- }
, M8 C; ^% @0 U1 c4 B
2 T) F4 _$ f! Q& D
* N; ?; B. E+ W! a5 G! n- public bool IsReusable% O& Q+ J: y2 r E0 _$ T
- {
) \7 |9 z! K3 W4 o9 X# y0 v - get2 @5 Z4 Q$ ^8 ]& |& F7 ?# h
- {' C% J$ n! S* s7 ` M# d
- return false;, S r- R9 W2 J f& A
- }
7 h* M' x' b# L, q0 ` - }1 z1 x! Q$ v) E3 W
- }
1 j7 e! c+ _& K: y9 L4 Q: I - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 + J' h! A# i j2 a( e% w0 W
|