|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 ! i% T& r& s% V! R
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;0 x9 s. I6 C0 Y. g8 J! d/ H, ]
- using System.Collections.Generic;, I8 G3 P8 p1 C" ?0 v
- using System.Linq;
$ V3 R3 `: X; ^( Y9 w - using System.Net.WebSockets;
+ Y: k8 c/ i3 D. b' m' |& N& { - using System.Text;0 A0 v* j5 g/ l. S& M$ }3 H. l
- using System.Threading;1 C3 |/ J& x/ M% c/ H& }
- using System.Threading.Tasks;
8 }' k) Z4 a5 k& p7 g8 L( b3 B - using System.Web;1 {/ Y' J H6 s& p& @ }
- using System.Web.WebSockets;
& T% ?" y3 \( Y0 z) Y* R) z
, Z+ ~& u0 x: _! h
( R* A% ?+ l% _: q! U) n- namespace WebApplicationWebsocketHandler* N1 n' h8 g5 x' r0 y
- {2 x7 s E: \4 g* g3 V. u! r" k
- /// <summary>1 r2 d" A r) \7 c+ B: e. W( h+ b
- /// 离线消息7 x: Z1 v: ~, S+ V* K
- /// </summary>6 z( c0 d! d8 f. b5 A" Y
- public class MessageInfo; n. l7 O6 ?0 Z1 ^+ D1 s. S! E
- {( B1 ^: R7 L* P; \( M$ J8 F, U
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)2 x n6 t( O+ t* k$ r
- {
! p9 l7 H/ ^3 y, r d9 W* I( m$ b - MsgTime = _MsgTime;
4 x+ ?8 d7 }3 F$ v- i$ m$ ` - MsgContent = _MsgContent;
, c3 ?5 I0 r! U2 Q! a - }
. S7 K3 J- B3 ^+ F1 X$ k, z - public DateTime MsgTime { get; set; }; j% f# Z' K9 Q5 a- m
- public ArraySegment<byte> MsgContent { get; set; }% O9 e. E2 O/ o% p' l, t$ K) H/ B; X
- } R( g5 F" }, F( F$ h
" V( P; R2 _( J6 p9 a+ C4 @% \- ) `9 K8 M0 Q0 ?; `- c9 T' f2 Z+ v9 q
- % l- b# ^& a* }% k9 N3 I
4 e# ^% q( D* X* t7 Q' I/ @- /// <summary>" r: ?# e' @$ v& \0 V
- /// Handler1 的摘要说明
) B- m* B" k3 h - /// </summary>
- m w) ~6 R/ Y4 x - public class Handler1 : IHttpHandler
9 |* q/ }, _9 b: w+ ^0 U - {% V* m2 z" J6 P
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池0 P$ w: m9 ]% Q8 E7 Y
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
- O( M& ]% Z- Y - public void ProcessRequest(HttpContext context)0 W# f, v( H/ S
- {
5 x8 `2 Z5 @ E - //context.Response.ContentType = "text/plain";! }' j1 T$ m% P# T" C
- //context.Response.Write("Hello World");2 B0 [6 @" E$ M3 s4 ]( g+ N# D# Q
- if (context.IsWebSocketRequest)! M. f* k7 W5 Q* b* D- y" }( l. o
- {+ i5 U' t8 F$ Y0 Z
- context.AcceptWebSocketRequest(ProcessChat);6 B) U5 E: ]4 s" O
- }
0 c0 e$ d. `; [/ o: r - }7 \2 R% W5 D% n& U) L" n5 Y3 ^" L
- " d" `2 T+ o E2 O0 `
- private async Task ProcessChat(AspNetWebSocketContext context)/ L" U- f+ i3 k. l) p7 q4 y
- {7 ^' w% k; y- Z4 f2 z C( q8 r
- WebSocket socket = context.WebSocket;" w8 D) [5 Q' I* V8 N n2 R' U4 R
- string user = context.QueryString["user"].ToString();& q( J( p) h* n9 p! K/ K
) e" w$ p7 @0 y' Z- try
' Z% W2 P. n' `6 `) J* d - {
- ]' P. ]% H$ e* {' G3 z3 r+ r - #region 用户添加连接池; N" M8 m! e) ]1 p
- //第一次open时,添加到连接池中
( k; {4 H9 [3 B \/ Q2 Y - if (!CONNECT_POOL.ContainsKey(user))
! r3 q% t: y$ e: \ [1 J% N0 Y - CONNECT_POOL.Add(user, socket);//不存在,添加
5 d! F2 I9 @/ {" F7 @ - else% J# p3 x& z3 L2 S4 \9 t& k8 X* Z" l
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新8 C( ]( ?1 w7 g$ Z
- CONNECT_POOL[user] = socket;
3 [2 x' |+ J+ V - #endregion
2 j5 Y3 [8 X# Z5 l1 C
. g0 ?; S( P" N5 v- #region 离线消息处理7 C! Y: r3 @! V
- if (MESSAGE_POOL.ContainsKey(user))
5 s6 b0 A4 c! u3 X - {# v6 Y+ T2 K* E
- List<MessageInfo> msgs = MESSAGE_POOL[user];7 U/ ]' ]5 O% c4 P5 i
- foreach (MessageInfo item in msgs)$ u+ b. g( L* \) `$ ]
- {4 \- Z( _( V+ j1 X9 ?; h
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);( B' J# \2 O( H3 k! P/ D9 I9 E
- }
3 H! E$ d# |7 R8 ` - MESSAGE_POOL.Remove(user);//移除离线消息, O5 ?" j+ P" \* J/ W
- }+ s( o8 q5 }; w, }5 E d9 V" @$ z
- #endregion- g! i6 O( j( N
2 R- y6 {& F5 O `2 u% ~- string descUser = string.Empty;//目的用户- a' z% G+ _6 `
- while (true)
5 Y/ A5 M1 U' F! `3 ]0 v - {
6 U1 ?1 T0 e, {/ ^+ T: t) n9 l - if (socket.State == WebSocketState.Open)- H5 _5 E) U$ s) b$ x% K: d
- {
/ `) w3 n1 p' K# }+ T& h. d - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
0 u' w: t! @; w" C# Q- F3 R( Z- ] - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
# p$ |; }" v+ s3 z; y& ]; |
- A/ D0 P% h2 s6 R1 v- #region 消息处理(字符截取、消息转发)% `- ~* `) X: F1 y5 Y
- try
$ }2 }3 J- K6 Q6 B$ E - {
- I; s+ R/ ], \4 x9 B0 t" B! F0 K3 { - #region 关闭Socket处理,删除连接池; }: @! L1 {: C
- if (socket.State != WebSocketState.Open)//连接关闭! \1 Z' _% x/ `1 h% m
- {" h& C5 R# Y5 `& Y
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池1 G5 w; s6 P( n4 K* Y- k
- break;8 s% Z/ U: R. w! M' X( P
- }1 V, i" s [) g( L: g
- #endregion
, ]3 V |* N( U8 c
: V, o% O0 w6 B. B* V3 [. {- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息5 L" z/ p7 @& p& f4 }
- string[] msgList = userMsg.Split('|');
) `' a" Q+ {; { - if (msgList.Length == 2)
$ ~4 E0 H* e' x+ K4 L# R - {
- s2 m% }! g) y1 P5 p. r - if (msgList[0].Trim().Length > 0)3 V \: ` T7 i9 q
- descUser = msgList[0].Trim();//记录消息目的用户
' j, ?% b0 Z; O4 Q" R+ W# p4 ? - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
# {* M9 n- H: }6 v - }
9 S* {3 s8 P( }9 Q1 M - else
2 V' T* w8 w, g* R, G# P2 s - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
" j7 h5 Q* h2 _5 m; { - , H: g7 [+ ~5 _$ W, |- }7 s
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
~- j- U! z- l" e" d- U1 u$ {, _7 | - {
; d/ Z) C6 |% l Q: e' M - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端9 k5 ]" K9 z8 o" z
- if (destSocket != null && destSocket.State == WebSocketState.Open)
/ f0 S+ |' d! K - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);$ F6 ]! E) f8 j( r# C9 T
- }; K2 ^# Y/ E e8 p" D, ^3 h
- else( _5 B& H% l+ e! @% w* k* _( H
- {
3 b, }7 l3 j5 W5 A4 V* q - Task.Run(() =>4 R9 h+ i5 }7 q0 N
- {
9 b3 D/ p( z. Y - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中- f/ B! o# O4 Y5 p' K+ Y$ a# [
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());, b, U; \6 `) p7 p5 D, ~" _' g
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息+ Z# \/ g3 U" }, s0 M! g
- });
& Z' x$ n8 o+ ?" v7 s, F, K Z - }+ `$ t$ i+ B6 W7 V
- }
- Q2 n% M! K4 l- x3 ~ - catch (Exception exs)
, Y+ K. @) C+ ~$ Y1 B6 j8 k$ Y - {
# C' z- a1 y; p. z# X V - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
: J. _* V! {* J6 }7 n# i }% `. H- e - }
& ^1 v& n$ L0 x# n3 ]5 w- U - #endregion; k1 Z- [& a% j9 \% X w
- }
m( b) A# D3 o - else! J; U- k2 g, H+ i3 S& i
- {* @* _, M6 m! F
- break;& z' f: N+ n& c3 k
- }
" J" D* Z( |$ j n7 l* t ~: m - }//while end
# x0 H; A( r9 g7 N+ ?; l! p - }; T4 P1 P3 q, D8 l: }9 T
- catch (Exception ex). X$ o( |0 H) o$ c: L/ I
- {
. C& p3 h% X4 u: B# q+ x - //整体异常处理- s, h3 z& ~8 i" n0 I- C' E7 B
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);* v( F- U; [9 M7 w
- }/ m, F4 z/ z/ g" [% [7 h
- }
9 O5 [; d; ]" J" j( N9 u
; x- q0 m3 G& r' j) _! Q' H
u- p4 w" j0 W( w2 ~- public bool IsReusable
' G6 b- {, o# D! c7 }7 v - {9 U4 Z+ y/ I. s
- get
( m+ U/ l5 e3 M- m9 M- U8 Q f) b - {
6 w) X3 h0 S) J% ? _3 m - return false;
! p9 K, K0 y8 {0 \" {- R" \' g8 z! K - }
- Q" Y+ V) }0 u! M+ c3 h - }
( A, R8 y, `, u - }
& X7 M& ~/ Q2 I% D - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
# h4 Z- l* M0 ]7 K |