|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
- G' f) W H# R2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;: R" ]$ W; t5 W+ p6 g$ f) p3 a" y
- using System.Collections.Generic;
( R7 `# ?8 V8 S; o6 ? - using System.Linq;+ M! y: p7 d% C, p* z" d
- using System.Net.WebSockets;
3 W, R/ O$ H2 u9 d; n - using System.Text;) j" Y8 I0 Z7 O% M4 u9 I4 }
- using System.Threading;: R! G0 P/ m1 _" G- j/ p5 P U
- using System.Threading.Tasks;
; a$ L- B" N. N* t: o3 W; N - using System.Web;$ F0 \& r$ ~; i0 I. ]
- using System.Web.WebSockets;
- i. |" q5 ^' ?( F3 L, Q! G - * A* [- I" o, j7 o
7 x- `# w% A/ S2 O- namespace WebApplicationWebsocketHandler
" `* ~* C" c1 X3 ^ - {
. y# w8 l3 L0 O - /// <summary>: W' @7 c, g! Q% d; k& h0 |+ \1 ]. l
- /// 离线消息; l! u `- G4 g7 H3 u3 G; B3 y; U! r
- /// </summary>2 J. }, V3 k) J# J' h8 C% J2 s8 N
- public class MessageInfo
1 `, m( r' b4 @6 S3 B - {$ ^+ W0 I0 u' v
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
2 P5 |9 e5 p# g: {2 |6 M/ V" X - {# W5 ? G [. Z9 ~$ ^
- MsgTime = _MsgTime;
4 n8 B$ t/ q8 A+ g) u - MsgContent = _MsgContent;
! p T5 \+ g; y, ~& O - }
. ^. S* ^ s5 `. `6 B0 ~ } - public DateTime MsgTime { get; set; }. R8 A) b% R, L, G: u% ?
- public ArraySegment<byte> MsgContent { get; set; }
8 ]) P( L+ j! s" _ - }4 N2 _- z9 T$ |! t, Y
- & M: Z# `5 v& P# F: O a
- & o, M, {. D, ~( e0 c3 {
- & E4 z0 W1 b5 M; A3 f) |
- : O( W G) m5 _( O/ p- T
- /// <summary>; o/ N8 Q& X1 C7 j' b3 O
- /// Handler1 的摘要说明
5 z4 \( _! i, v - /// </summary>
; [6 z. `9 L) |( F2 i0 t+ ` - public class Handler1 : IHttpHandler5 D& C' F C" x- g8 l) H
- {. a* p s% p5 f) n! P9 x# X- [5 D
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池2 T3 [) d7 K5 W2 w* P: \/ w2 k
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池 C% H# v6 W, i s' _
- public void ProcessRequest(HttpContext context)0 J8 X. _# B' F9 f: M7 ^! S/ \. K
- {! W# L' v2 w, | j
- //context.Response.ContentType = "text/plain";
0 x) S- c! S; u! \2 b% |6 W4 a5 B - //context.Response.Write("Hello World");
# q- C8 g1 p- T q( H6 C - if (context.IsWebSocketRequest)/ f' P* T- b+ f
- {. r+ Q2 [! u& a$ g
- context.AcceptWebSocketRequest(ProcessChat);
7 V3 f$ P3 I) `! _0 h - }
3 S& `! {9 y) i* \" j, `2 _3 P1 h - }0 W; N+ g* T s" y4 p; |
: G8 Y2 T% ~7 l6 G7 f- private async Task ProcessChat(AspNetWebSocketContext context)
& a& d1 @4 N4 Q" n+ M8 \ - {' O4 V( ]. B5 Y ~- H2 T
- WebSocket socket = context.WebSocket;
$ k: o# m1 L/ y - string user = context.QueryString["user"].ToString();4 N4 @/ E+ \& {
- ^1 E( f4 i W, L4 Y3 o
- try
+ a% p2 l; n8 {9 l R @& y - {
0 T4 h% E! i/ j6 d8 _# K; C/ @ - #region 用户添加连接池
9 A2 Y! k! f0 y* K& d - //第一次open时,添加到连接池中$ Z+ K+ E# c- Q6 H/ g- K. o3 u! P
- if (!CONNECT_POOL.ContainsKey(user)) z6 ]0 H( r6 H0 c( k7 ]# f
- CONNECT_POOL.Add(user, socket);//不存在,添加
- \+ R3 [# m) a! M0 P - else
9 J2 j0 m# s$ d0 r9 W - if (socket != CONNECT_POOL[user])//当前对象不一致,更新. F+ m \# y! H9 o- ~2 x
- CONNECT_POOL[user] = socket;( w% l6 H% R( a2 ?
- #endregion
" X- _2 t1 c2 j0 X0 i - 5 D: _. \) P; k
- #region 离线消息处理1 w/ t& z# h5 x
- if (MESSAGE_POOL.ContainsKey(user))
$ @% P1 U) n5 X5 L5 I: @0 [$ | - {- Z8 i7 G: H- i6 H
- List<MessageInfo> msgs = MESSAGE_POOL[user];9 X& e; k5 V/ w
- foreach (MessageInfo item in msgs)
. H) N9 v; {$ }8 d) v/ ^ R8 g - {! e- U1 H. D; W$ a* d9 M, ?" T
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);7 L4 v9 t4 a L/ l8 H+ {( H( \
- }% K' P' X% g* e0 l! S* b4 u8 o
- MESSAGE_POOL.Remove(user);//移除离线消息
" D$ ]! M% n9 [, _1 t - }
/ w B7 `2 K1 @; [1 z - #endregion
( r0 t8 w' G( S - ) P6 T' p x' f6 }- D, q
- string descUser = string.Empty;//目的用户
) a7 |6 O0 n2 V% W4 }" ?& j0 d" t - while (true)
. [( r1 q$ G; G+ d" {% z4 Z. { - {4 {% c% [" U0 Y2 `
- if (socket.State == WebSocketState.Open)* l4 R* |, b0 N s" d
- { |9 P: V: N7 b8 c- C
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);3 @" t4 Z, [3 O
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
- r7 ]9 O) q q6 c8 |9 S' v% n5 T$ p - ) }! h! e7 D" R* \6 e6 G
- #region 消息处理(字符截取、消息转发). E/ }8 \/ f# s d+ s2 v! i4 F/ Z1 e
- try
6 x( [0 I& o- \. m5 h, Q - {; `( m) o. z1 L% g/ K$ O B T* F
- #region 关闭Socket处理,删除连接池
; p4 W! e( e2 H - if (socket.State != WebSocketState.Open)//连接关闭" f8 z$ L* ^ [/ e; u+ L( u: n
- {! C' x! y5 `# |8 P- m$ l
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池6 g8 A' n, f0 f6 c
- break;8 {" g C# k3 V$ u+ q; G
- }+ A( ^4 \0 F, ^& l$ D) R8 h
- #endregion
1 u2 t8 j! ]7 n& v% x" } - 7 e( l3 W: z7 l# i/ h- Q
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息. n, ~3 [3 P1 j* O) V5 h
- string[] msgList = userMsg.Split('|');3 j& {2 Q5 F/ o+ `, C* O* s+ ]
- if (msgList.Length == 2)) E! d! }' X- k
- {- U3 o4 h ^6 \7 U1 m. F
- if (msgList[0].Trim().Length > 0)7 D8 E1 B1 I5 p' @6 B
- descUser = msgList[0].Trim();//记录消息目的用户* s7 p! S) o+ ] C. o9 j5 ?
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
0 o5 ?3 ^- s) v; ]; c9 M. q - }
4 {0 W# J! B; f; a - else
: t# H& w4 `: j( I- g - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
- u6 e! B+ C0 E7 Q; C - ( W6 u" m! M3 |$ f5 d& V
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线- c% a1 C6 [9 V! c
- {
2 u* e8 [6 j9 H' u' G* N* C - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
' P) M( Y4 G/ V: X: v - if (destSocket != null && destSocket.State == WebSocketState.Open)( [* ], [7 @3 ^9 c( r
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
6 x: F. @( V3 ^+ [( @ - }& C% [% x3 H+ Y2 }" f' D7 P
- else8 z8 a( Q& X" k& K) H( Q
- {
" G! g% `& F. D4 C- }) d - Task.Run(() =>
2 J1 s, @8 X: q8 ~ - {
5 @2 R* O7 m! h4 v" Z n - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中/ F) {& U4 f6 ^& u1 k
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
: T7 b! k* o* M4 U - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息$ o8 b1 c2 J% w+ [) [& ]7 Y" [ ^
- });- Z4 M( R. m- ]
- }: _/ {$ J- L7 H% w5 K6 S
- }. p/ A4 F, n. N5 } A" U
- catch (Exception exs)
4 C. d' k& k7 z- L - {
/ u2 u/ M: k+ W7 M+ i - //消息转发异常处理,本次消息忽略 继续监听接下来的消息3 c" A* q) D; _+ L; F
- }
: w: J3 k4 V' P+ }5 ^# V4 S - #endregion
3 V0 }( {9 r1 H/ V. G0 T1 N" u - }! v9 {6 i4 _, {$ V
- else
2 z# y: c& l' }. k: T- r+ |: D - {
7 d$ D1 K4 r7 G# q( @* Z - break;
% {! D0 `& X% |1 ~ - }7 ?1 G3 @; K' B/ ]" ~) \
- }//while end
" e) }+ f2 P X( ]) s# L - }
$ F2 c* a1 Y4 f4 Y ?6 I# v - catch (Exception ex)' H. c3 u2 ?1 i+ B% k: k* u5 L
- {" n) K6 r3 w& k! F5 O
- //整体异常处理
0 D, _9 B# G* n: S( L0 r8 e6 o - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
6 N- N8 I) h0 S0 G) p& K - }: `% ` m$ c7 Z& K S
- }
# c9 x% P- b/ \- M+ r+ p - |4 g( k* L, O
- + B2 B1 J, V& Q5 z) K* g7 m' C
- public bool IsReusable' {' P" C: S. O5 e
- {
6 j( b. N+ ?# g- ~. g) [: t6 C; y. D - get
- ^; Z& Z1 n% l% x5 @7 {( ~) G& a - {
' J- m( J# ]7 `, ~4 c6 O0 v - return false;
2 ~6 L* i k; M - }
! w# o4 r/ d2 V5 R. n7 l+ j3 p - }6 T( ~! K6 Z4 r8 i+ d- ~
- }; p! X6 f: `7 A! t8 @/ w1 u
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 8 v& o9 M1 |; y( U/ _2 _; R
|