|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
( a# A9 b' ]4 v3 o2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;$ `9 y7 e( R5 W$ r
- using System.Collections.Generic;
$ y3 J, M2 W1 @5 p0 u6 I4 a - using System.Linq;) f1 N/ X3 v# s/ ^2 C
- using System.Net.WebSockets;
4 ], g! m0 q9 X - using System.Text;
6 ^7 O5 J% c0 L# D6 W% C$ L. y - using System.Threading;
( X# W3 [) ~: F9 {! O6 O - using System.Threading.Tasks;, p& P# v: o% _5 T+ i
- using System.Web;
- n3 {+ ~( F) p9 F6 ?/ W5 D - using System.Web.WebSockets;& G# p1 l0 e3 B4 o7 J* l
% c7 f4 C% S3 i$ P$ ?- B
" Y7 v# V4 g \0 l: Q% ^4 Y- namespace WebApplicationWebsocketHandler
0 a6 O8 Q$ Z! ~5 I: ]# Q - {
: o; _- D) t# T* u& k7 i7 } - /// <summary>
6 H! c. D# H* C) I6 o5 K0 h$ w5 l - /// 离线消息
5 c' O4 e- G) Y1 W n4 | - /// </summary>
! j" }& O" y6 L - public class MessageInfo
; {! p# v0 X2 P - {$ n8 R* E- r4 W
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
" B. f! n( A6 }" X1 v2 x4 } - {- e' T- y) Q, c6 [8 k- S/ c
- MsgTime = _MsgTime;) T. v2 {2 z5 j0 ^( |8 T
- MsgContent = _MsgContent;
' Q1 P, F ?/ R8 X - }7 J) ^. Y& V" Q+ f6 E. s
- public DateTime MsgTime { get; set; }& I+ _6 `8 W( K6 O: X) f; `% V
- public ArraySegment<byte> MsgContent { get; set; }
# w Z8 x; _& h2 W% l - }2 X* Z) Q9 S" k, o/ H
: S4 x/ H8 `, a; C) a( }# U- 3 k0 E3 u/ i) i. C
- f; l, n$ c5 |" ?( w
. y0 t. k2 g4 r7 A8 u- /// <summary>
+ U$ v/ W+ j% }" c& A7 q0 m, n - /// Handler1 的摘要说明/ H2 h$ z- J' X" L9 D$ r
- /// </summary>" N: Q4 {7 X8 A
- public class Handler1 : IHttpHandler+ w6 H% o* S5 \8 m7 ]: ?% B7 \
- {
6 ?( v$ Y3 x+ { J! y, Q4 H - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池2 d8 V3 M/ j6 z1 i% R: g# }+ I8 h
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
* y3 z2 N- U4 f# u/ f0 ^5 _- {! m - public void ProcessRequest(HttpContext context)9 Y3 c+ f! f4 [" ^7 ^ M
- {% v8 E9 v7 K1 A j& C% N
- //context.Response.ContentType = "text/plain";/ A' k r3 ~, v6 C0 x3 x7 @; G
- //context.Response.Write("Hello World");
& s+ E z4 G* ]1 @ - if (context.IsWebSocketRequest)8 {5 o0 h) n% w. k [# S3 ^3 |
- {; P) t; C; Y; i! E
- context.AcceptWebSocketRequest(ProcessChat);
0 {, i8 M* ~, V - } ?2 h& K/ U$ B: H# c0 @8 |
- }
: Q- d# j3 a9 A! m5 ?, ^
5 c! q! e5 |% @! C- private async Task ProcessChat(AspNetWebSocketContext context)
/ d0 v9 ?* ]" F% A- H8 m - {
5 Q' L" f4 B% P5 @- a+ C - WebSocket socket = context.WebSocket;' [) _7 ?8 K4 g, {' Z/ m5 }7 d! P
- string user = context.QueryString["user"].ToString();
: x6 z$ o+ Y0 u0 [2 r) ~1 F
& n# ~. `( h) y' a' }# j- try- [+ q1 V! }' w3 E4 d
- {
2 C* G# Z! z2 `" }. | - #region 用户添加连接池) p+ ^) |$ U( q. W
- //第一次open时,添加到连接池中2 J6 J) n; X: c9 P" s( l
- if (!CONNECT_POOL.ContainsKey(user))% c: X9 a8 s1 P1 t8 f" J% R
- CONNECT_POOL.Add(user, socket);//不存在,添加
* V1 a' x; L) F( J2 W9 W$ I; M. e - else; q) | Z; ~% z( o
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新 z" C8 T5 Z9 k3 P% B2 R/ Z$ |3 Y
- CONNECT_POOL[user] = socket;- M& F/ A! u* }) P8 C1 \% k% l& e
- #endregion' J, k( K8 j" e
- e" g6 J& y# K- #region 离线消息处理
! K% H: u; {& V' P+ |- i - if (MESSAGE_POOL.ContainsKey(user)): z/ Q' k+ D/ r! J2 d" y
- {9 O% p$ W( r4 `/ y+ t
- List<MessageInfo> msgs = MESSAGE_POOL[user];
% {! Z1 F. r, `, V6 Z+ [8 v - foreach (MessageInfo item in msgs)* Q- H4 y& ^$ I. @* y8 T3 [1 ?
- {
' d; {$ U9 _3 |# U3 [, @4 W9 L - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);! ^# p% H x2 o" E' ?
- }
5 Q8 ^7 t# n: c k - MESSAGE_POOL.Remove(user);//移除离线消息- U6 J9 n# L7 u: P
- }0 B0 t7 T, M/ x
- #endregion1 c: \* H& Q& `, N. h8 _2 Y
9 E/ d: g' U/ l& {! |3 |% a# _- string descUser = string.Empty;//目的用户
8 c% V# k% l6 v6 @% L - while (true)
: d5 j* q( L9 i, e+ g! x - {2 L7 \1 r6 B% }/ O4 ?5 _' a
- if (socket.State == WebSocketState.Open); ?: t |' H) Y9 m3 o2 ~8 u
- {
" S( c/ S4 e5 S1 I. o7 h - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
! [; _1 K0 R4 N/ G3 S - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);3 X4 Z+ u! M: }( R9 R
* q( |7 C+ F* ]+ }$ @$ b- #region 消息处理(字符截取、消息转发)
: n: d! S" j3 n" } o3 b) N - try- m) q( n# n9 y- _8 W
- {
1 r, B0 y9 r2 N. x! z' S5 L( P - #region 关闭Socket处理,删除连接池. Z7 o& S/ }2 O6 @0 E
- if (socket.State != WebSocketState.Open)//连接关闭 m. X8 G7 M0 n- z( ~
- {
4 @6 b: r4 q7 m; |0 X6 G2 ?( x+ `' X - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池& _5 J' @: j) e) p3 O
- break;
7 F8 C% g! e0 ~4 U1 C& ~4 V$ l+ l* o' ] - }; y5 h h* j/ m" o P7 e5 I
- #endregion
* }; h; M/ X+ {# V( i
8 F2 g$ ~7 f4 G* W+ Q; J! [- Y7 p: |! u- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息1 }+ x- g& o2 Q* l! ?
- string[] msgList = userMsg.Split('|');5 O& H- U4 X. j: I: Q+ E
- if (msgList.Length == 2)5 k8 H* z: P# u8 H
- {: M' O) m% n, c/ ~& g
- if (msgList[0].Trim().Length > 0)
$ X( _0 S1 z0 u2 i0 E7 D - descUser = msgList[0].Trim();//记录消息目的用户+ c$ W: u7 b2 R0 ~
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));* H$ V h* o4 @& x
- }
) t9 g( |* B/ y/ @8 Q1 c! ] - else5 T8 U: j! k0 O& n! _4 ^ c( K
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));# E; X& ^, p$ D8 y1 Z
- 9 n Z) M) D( H, X( {% }
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线* e5 q4 `, T/ g! W) R/ F
- {
2 P/ Q/ K" ], b - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
' k( z& u6 V$ F y% L - if (destSocket != null && destSocket.State == WebSocketState.Open)7 g) G5 _! _' b! m- j8 }
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);3 y3 G/ B7 E& n3 s
- }5 R) I8 Q& S$ W9 k' M: ^+ p
- else
5 r+ n. {: L/ V* B0 f5 F- Y - {& o6 I* i8 i, B0 r
- Task.Run(() =>
1 w7 N8 _- j, z2 h: N - {) z0 w0 ^, A* L, D* h6 Y: y
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
' G& z+ |( B9 n - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());0 {, o E7 K1 k9 E% E; m9 z
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息9 }0 b% E4 L& ?3 W' }" O. K
- });' ^6 }( M) Z6 z+ I6 U8 W; i4 c6 N, z
- }/ W) i1 q7 J( ?4 ^
- }
6 C6 M& E3 f0 h" t - catch (Exception exs)- U6 N4 L! k& O4 }* O( ~4 Y- n6 X
- {. j5 U% U$ V. Z: A( _. A9 H
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
1 N4 M0 M: N: y - }
! M5 r3 B+ ^7 F. t1 g! s! B - #endregion( Y/ t. u8 C0 _+ T4 T# C
- }% F Z; S: a6 H
- else
9 q' k9 r! x9 e7 F) E - {- y* L3 q0 t. V4 t1 y0 Y9 |
- break;( j8 |1 y9 v U& h
- }
; H5 t9 J8 e- n, g5 o+ Z$ x; Z - }//while end
: k; N. D6 g3 M/ q e - }
% T0 W! u; |! B" @+ X. R. ^8 q - catch (Exception ex)
+ c/ Z7 o$ Q2 }) B( `/ L: A - {
6 l9 M5 g$ }. q2 `+ }! `0 f - //整体异常处理. `$ X3 g+ H& Q2 A( h
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
; }# P" Q, w) ?" \3 ]$ h) f' u& l - }
1 N- A9 a2 t" O4 x* l- U - }
! u/ q! d1 s* K/ Z' m* J9 E
+ k, F6 J/ B2 Y2 e3 B
, }; H! ~' H6 B( T. S- public bool IsReusable
" x# q8 g% @1 p! Q5 P2 s - {0 z0 c9 @% j4 d- J1 j
- get$ p# Z7 Q; x: N$ d1 t! O! d I0 D
- {
( r+ K+ z! U9 W7 d$ Z1 U3 ? - return false; G' O3 z! N f: i
- }
) N5 S+ r; i- ~, K - }
4 m" O# B/ [5 _8 F& _1 A - }
5 c; A8 |: ^0 Y o! ]$ g5 M/ Y - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
+ Q( T1 Z @% M+ ]1 Q! D& w |