|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 $ O8 F: n! N- s
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;" F( K0 ^# ]( n+ e2 N. D0 ~% |2 R# J
- using System.Collections.Generic;
- M j- c3 w/ P5 { - using System.Linq;
" B" q+ D7 A/ A1 S+ Y- E - using System.Net.WebSockets;
% w4 I& S% r- A4 B( b: Y: w - using System.Text;) K, D: o0 [' |+ P' P3 N( v
- using System.Threading;' }: K# \5 k+ B
- using System.Threading.Tasks;
( u1 z' n* M. _ - using System.Web; G# q( k. N! P" Z8 |
- using System.Web.WebSockets;9 z5 b: g5 S2 O* G' a
- G6 d8 z: U T/ ~ M
* r, O: [6 N% a3 [& e) P- namespace WebApplicationWebsocketHandler1 c& O4 p: U' H# y2 Z
- {2 ~+ t- |2 s) g- t8 f
- /// <summary>
: @$ t% W9 J' _8 ~- H+ w - /// 离线消息8 S/ L- i9 Q4 q2 w: z$ o
- /// </summary>
8 H2 y/ ]! A; d( B - public class MessageInfo
+ Q4 o0 p; u$ p - {
" @/ I. j0 p6 j" T6 B: u - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)8 ]/ M+ L1 K, L
- {
2 F" f7 I9 W- F8 L7 _ - MsgTime = _MsgTime;+ T2 e- c' V3 A1 n; q! Q1 S w' g
- MsgContent = _MsgContent;
}+ `! z1 v3 I! d7 q* O, g - }2 r6 y& q) N1 M4 b7 Y0 Y( j6 f
- public DateTime MsgTime { get; set; }3 ] b2 y7 b. G% {& ^) d5 A
- public ArraySegment<byte> MsgContent { get; set; }( P0 d! i: J2 l$ C# d8 ~
- }
. _ B( }9 Q2 x1 O) r& p
" Y; e+ a4 v F4 C _
4 b# O7 [9 q/ X. D- , u) N+ q% j0 d! K
- 9 l- A, m7 \1 e6 I" l: L
- /// <summary>$ j1 C7 i+ u8 ?' P8 |
- /// Handler1 的摘要说明
1 ^& M* e2 D8 P9 } - /// </summary>
+ D& `9 {* S; v - public class Handler1 : IHttpHandler
[* X. ]8 e( q+ p2 i& ]# c2 { - {
9 \- z' {5 U; K% A( c! x - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
. m4 J. m0 a7 n% {, S- ^& ~( Q, J( m X' v - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
+ ?! h8 m! O W- r2 J% f1 Z - public void ProcessRequest(HttpContext context)
+ H: J" a2 r* i/ M/ E. L - {$ ?! z/ Y" P7 W, r5 b' y
- //context.Response.ContentType = "text/plain";; }: J( n& w# r4 h5 j- F
- //context.Response.Write("Hello World");' \9 v3 c% g0 |! ^: u
- if (context.IsWebSocketRequest)6 U) ]; ]7 [3 C# }, u
- {
2 p. `8 K# P0 u$ l+ L0 A4 c J2 R - context.AcceptWebSocketRequest(ProcessChat);' O! Y5 d; X: ^' o; u
- } " c* Y4 L% a7 A( _
- }5 J: _& f+ u6 }0 ~4 o
- : r8 D% n" D( T, b% X
- private async Task ProcessChat(AspNetWebSocketContext context)6 T+ y3 t$ U; ~: E3 i% j* ~
- {8 W! b2 e& \4 ?( r7 _
- WebSocket socket = context.WebSocket;
4 N) l! X7 o7 R: m - string user = context.QueryString["user"].ToString();% ]0 l# J" N/ r% _
% r4 k5 b0 H* i2 k- try
3 f% c3 X8 t8 B - {# S7 R; n9 T! X
- #region 用户添加连接池! f9 W- i' B! i
- //第一次open时,添加到连接池中
, k x; v) w( t! N. r; I' T - if (!CONNECT_POOL.ContainsKey(user))2 h6 R; e/ n0 s8 j
- CONNECT_POOL.Add(user, socket);//不存在,添加
# b+ @( P" J! F4 }8 ]; J4 g3 `5 t - else
) t2 {" h; |5 p1 v5 D - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
% ^5 c/ d$ Z3 L9 n& K! ?( I - CONNECT_POOL[user] = socket;
7 t# `5 J# Q @9 i/ D" f - #endregion
+ N m) P1 }/ k Z7 P; l
9 N3 }5 p1 |" o) z! K6 t+ o) C" w6 S% V2 c- #region 离线消息处理
3 K/ g/ K3 h3 e* r G5 R) V7 x - if (MESSAGE_POOL.ContainsKey(user))+ p1 O: D# t# G% O( G
- {
6 T2 @# e% @0 t! m; J% F! M - List<MessageInfo> msgs = MESSAGE_POOL[user];9 E, O$ p- u9 x- v
- foreach (MessageInfo item in msgs)
' V) q5 s6 u* O7 F% | - {
* ?; o, m! E5 ^1 B2 N - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);4 D4 q. a& j4 U% y' y
- }; B3 N/ p% Q% A9 z. h
- MESSAGE_POOL.Remove(user);//移除离线消息0 N& t( S3 M3 f
- }+ x4 t' L* ?* T6 Z2 z1 ^
- #endregion
# z! I) C, t6 e$ d" | h/ l. `# x! ^; k - M0 r4 c% A3 T2 Y1 [
- string descUser = string.Empty;//目的用户4 O% T& |6 H5 z9 {: O
- while (true)6 _4 A' N; v: ^6 e
- {+ `4 b4 I0 _; W+ Y3 Y; F8 ^! J
- if (socket.State == WebSocketState.Open)% r5 V/ U6 g) h6 K2 d
- {- z+ @/ U& c" j7 t
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
2 A3 B" N; k- c- S0 V - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);: ]9 F# e8 H$ C6 S! Q/ `8 v1 P
- & @( I ?" D. T
- #region 消息处理(字符截取、消息转发)7 W: _7 f: Z! ]1 _% a
- try# {8 P- c: J- Y- u: g. e% U p5 \. Y
- {2 s, p" @; o) k; O
- #region 关闭Socket处理,删除连接池6 ? ?# \( P& k+ h1 {
- if (socket.State != WebSocketState.Open)//连接关闭. }" E$ `' n# [ S6 s
- {
" R, J2 I7 S6 z% T. e - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池6 b6 _( H9 o9 X
- break;, h& S; c, ^3 X1 |" `
- }
# B; M2 T0 s1 I, q* u! t; ~0 Z - #endregion k9 H4 _1 N4 S1 e; b
- 7 B$ S; H: ~+ F" J
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息% } z$ h( v- h5 P$ H" ?
- string[] msgList = userMsg.Split('|');& I: ?0 q' A+ ~% v
- if (msgList.Length == 2)
# I# g+ n1 K5 j9 E - {
) K6 s1 c0 @! {1 y4 A2 k7 T8 S - if (msgList[0].Trim().Length > 0)
+ \1 s+ Z5 n$ g2 X" s$ S0 Q3 y. ] - descUser = msgList[0].Trim();//记录消息目的用户
" o+ R! n. y: O - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
7 {. p0 z C5 V# M! q - }7 W5 J1 e- `9 X& w8 [* b
- else! O8 B0 m4 J1 p9 _! W9 X9 C
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
; m F* o4 J$ R9 M# |
9 m/ j' w. @8 f8 {) t- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
9 ^6 j) A4 R+ g - {
" ~1 o3 R0 _4 t+ D/ Y; x" G - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端* }- S% h! Y3 H$ G# L
- if (destSocket != null && destSocket.State == WebSocketState.Open)% g& K3 v- Q' [1 p. U3 @
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);& A2 m* f/ X r& o7 A; G$ y+ S
- }
. X" R% X. A# u, i3 U& E - else
1 }+ S' j2 o" y" s: j - {
8 j# Q u2 h( s/ o, A0 l - Task.Run(() =>( c8 b! F+ N/ l* n
- {; T" a' v. j4 {4 k
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中, d8 M7 F! C9 ~# ^
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>()); H A2 h# Q! f5 i) ^8 m4 k @
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息% j e7 w4 D( s& ~( \
- });# a/ ^3 I3 V: M6 ~2 N. n
- }9 j$ b' P# |* U0 w
- }7 h6 y/ J+ @5 p: i8 r/ y4 @
- catch (Exception exs)
( |1 p8 d: `' b% ?$ T+ h# W - {
2 s; j- ~; [$ q - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
4 J) S0 Q& L- @/ h3 U3 n- a8 D - }: m) T, |: W% S( q1 J9 c/ v9 u4 \
- #endregion6 H/ J% w D. ]0 x6 H
- }
/ i5 p/ i8 f8 x" p - else% ~0 y$ V5 ?+ ]8 z9 d
- {
: [' P1 B, U% c$ k4 O5 N! @ - break;
0 [0 v* g$ _$ S3 y4 c - }4 d! n. S2 [! c
- }//while end
4 j; h5 h3 L2 ]% u3 a8 \ - }
) C) Y; f+ b* A$ D9 Q - catch (Exception ex)! L; U0 ]7 }$ B4 s
- {' Y- c5 n* k' }* ?7 ]& x
- //整体异常处理
6 s( d9 n$ `) x# r - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
1 r2 V/ _! J% P; q6 L: e3 j( `4 e0 d* E - }
; H! J+ r; s: U& e. k# N3 v% @9 G1 q - }8 g6 B0 R' E1 I( q- m: I8 h+ o3 H/ ?
- ) `! K4 p) q- {
# P% d; K8 S+ ^; | D* }- public bool IsReusable
$ u, ?* r9 ^, K% w - {1 P: c; i1 K6 }$ H) N8 T( h
- get' |' m# `2 _( K3 p1 R/ C
- {: ?3 n2 C9 Y3 j0 H) y
- return false;0 [ W* X# M5 q
- }
6 k( e) a+ ~7 T/ c9 f, z! } - }
7 Q+ z8 y U2 p: [. H3 D# F4 b# s7 o - }
6 ?- X4 ]9 T, e* A - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
7 j6 S+ Q* a7 I8 L1 B' m4 g |