|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 % W* s2 K9 q) |; D
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
) o0 n. G! O; a: k - using System.Collections.Generic;. |+ L( l0 i, ]+ G8 Z( y. A
- using System.Linq;3 r% \4 Z) I# T- S$ N: g6 J1 b7 p
- using System.Net.WebSockets;
6 a" y0 w3 u0 r8 i! v7 x6 e% d- S - using System.Text;/ B3 f6 ~4 f( f, y% ?
- using System.Threading;
8 U: R9 P1 k2 Q! y - using System.Threading.Tasks;
. ^2 o% o- e1 h8 G - using System.Web;: i C) b4 S- T2 Y. e# p
- using System.Web.WebSockets;# ?/ k) S# O9 ?
- ! G/ m- C" O9 [8 t1 x
- , a; ~9 i9 Q: u" ^$ V& {) D
- namespace WebApplicationWebsocketHandler
$ n9 d' S) x' U. g' `( ] - {3 F. {5 Y; K0 z! B/ T! [1 G: x
- /// <summary>
, |) W0 s) f2 Y' s O( Z3 c9 m# a3 H - /// 离线消息* L' L, s# w( r1 R; d2 _9 F
- /// </summary>
6 U: M4 u1 O! T, ]! y% p2 l6 k - public class MessageInfo
) c( X( m- Y( k' _' W/ q! p - {
* B6 F. Z, e# x; s - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
( Q: q. v1 Q) Y/ ^/ I! B" q - {
3 `1 t7 K8 t3 ~: X0 E9 c- u h - MsgTime = _MsgTime;! a" h- R/ l1 p- }7 b
- MsgContent = _MsgContent;4 \* S' `9 R7 w3 |
- }
6 r7 J1 E. p# c+ V! ~ - public DateTime MsgTime { get; set; }
# @6 Q+ L2 C( X- S( M - public ArraySegment<byte> MsgContent { get; set; }
) Q+ g1 Q; C0 ]7 Y2 J% N$ V - }: B. k& l$ b( r }2 s
' a) M0 h+ _+ P5 G4 j/ M1 ~0 l- o# M: Z3 Y7 ~! O h6 z
) V' c+ ^# Y/ V( K+ k, W- ; Y3 D) l8 }. o8 u( c- ?; u5 {8 l
- /// <summary>
1 p( f3 q& g# H - /// Handler1 的摘要说明9 P9 W) @! c. n3 l( y
- /// </summary>
! @0 U. {$ `! }1 b$ w2 u/ i. e - public class Handler1 : IHttpHandler2 o9 |& Q# H1 G6 u5 V8 h6 ]
- {
: Z. l0 O0 R; q8 D( y8 O& [3 W ~ z - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
9 v1 B" l: L5 b - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池3 r7 D! v9 T% B0 g0 A6 U
- public void ProcessRequest(HttpContext context)3 }; J" r% y: x! k5 r" Z
- {
- ?0 w% q% n% v0 E& D - //context.Response.ContentType = "text/plain";
$ l g/ I0 i b( V: U# ~) P$ ~ - //context.Response.Write("Hello World");
- j* j! w) |1 Q) R$ A0 x" m - if (context.IsWebSocketRequest)
1 o9 o/ c P$ C8 D( s - {% V5 p- j* Y' P+ i2 i
- context.AcceptWebSocketRequest(ProcessChat);2 ?7 T# r" K* `9 e
- }
7 M% i% J2 V1 z - }' w4 G" b0 {# D4 y: ~2 I
# h- o+ S" l" w0 }5 D& D- private async Task ProcessChat(AspNetWebSocketContext context)$ ^6 U2 ~/ i. n% i; u6 x7 U# C. v
- {
8 g5 e0 e7 t. p& P2 A - WebSocket socket = context.WebSocket;! h7 ~4 T. h0 b" Y
- string user = context.QueryString["user"].ToString();
4 z, c) N E8 r - $ \- i b" ~6 G
- try
- r6 w$ m' F0 t3 `8 N# z3 m - {% |/ F/ _2 w. ^/ Y$ a5 X( |
- #region 用户添加连接池
% B9 X+ k* d- @7 ^/ b! @ l$ C - //第一次open时,添加到连接池中8 \) Z* J% V0 W, y4 S& R9 V: I$ Z: C
- if (!CONNECT_POOL.ContainsKey(user)) S% V2 ^$ J$ m$ U7 t4 p. q. w
- CONNECT_POOL.Add(user, socket);//不存在,添加
- B: S }/ Y4 A( u( d - else
( O& t; |& E! y1 ^ - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
; F4 h+ L4 b' [# i9 \( s - CONNECT_POOL[user] = socket;' z) T# { M% r
- #endregion/ E5 B0 m" Q+ N8 t; g
- C7 c* y4 h2 P: e& x
- #region 离线消息处理
7 b Q# j2 F2 T8 e. |1 b - if (MESSAGE_POOL.ContainsKey(user))5 Y9 o: n: D* v
- {
M6 [" l6 r7 N7 [ - List<MessageInfo> msgs = MESSAGE_POOL[user];. C9 \8 D" q3 b
- foreach (MessageInfo item in msgs)
$ d2 {* {/ k! n4 }1 C - {
% a' P: u+ V6 E* F# H( t. ^( o% w - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);# o# t8 l/ O$ d/ F& {7 H) U. t
- }7 L/ D' |$ B' u
- MESSAGE_POOL.Remove(user);//移除离线消息
' f' H# r2 t1 L* @% X& W - }
' t: ?: a: N& o1 P* i - #endregion! h$ U. j0 D2 o+ D6 P {! R2 s
' [0 B2 L6 i- T, p- string descUser = string.Empty;//目的用户4 C3 r% d }0 D( J, K
- while (true)# s5 B* X% }" u+ k
- {/ ^, ?3 t: k v' Q o$ i l
- if (socket.State == WebSocketState.Open)
& V3 b+ ^# ~( f* ^8 h) ~( h3 k0 S - {/ P, ^/ \. ?/ ?& X! e
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
) L# e; Z6 [* n# a% a - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
% ]' B# X E: X7 z, D& l6 x0 O& T
! I3 h9 e9 q P6 x2 R& j1 H1 Z+ Z- #region 消息处理(字符截取、消息转发): C4 i. y' C E
- try+ f" a. k! i7 o5 v
- {
! h, [& Q! H$ }+ Z# e - #region 关闭Socket处理,删除连接池" d$ G {9 p5 q9 t6 c; z3 x3 k4 q
- if (socket.State != WebSocketState.Open)//连接关闭, D* R( m3 C6 |6 @. q9 W$ ]
- {
# V* X7 S. B* ]7 w - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池$ l+ M% ]$ y; u8 ^' z* E
- break;
. m% o" u! ~$ f6 | - }$ h4 I% ^5 P3 f/ O9 M: I# O/ r
- #endregion
! y4 _( ^$ T5 X - , H5 O, ^' X( E
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息* z# x ]& h# ~' b9 X
- string[] msgList = userMsg.Split('|');
. q7 a/ {! k& J2 M. f: G - if (msgList.Length == 2), ]4 U6 Z V8 Y3 I& h! U
- {
/ s1 W2 H9 k# Z - if (msgList[0].Trim().Length > 0)$ u" v* c% X1 m, X- | }
- descUser = msgList[0].Trim();//记录消息目的用户, W: f1 W. q0 u% k6 C. L
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
L9 M7 g* ]/ u# Y! W - }
" v- g4 S3 t1 r6 r - else
5 T5 o8 v2 u( F I( X. ]% ?& J& ^ - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
; G' _; k! Y! l; E! i
9 C- M6 i5 Z& W) \ }8 Z- h( b- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线* T/ T7 D! f8 x7 B3 U" T3 q- g
- {0 Y/ Y& R! m3 v+ q. w
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
7 R9 I: N: T, A2 `/ _0 A- I - if (destSocket != null && destSocket.State == WebSocketState.Open)4 z8 E- D' u$ a! R
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
+ p" Q1 z" w9 v- G8 I - }
: T! \2 [6 V! A: a/ k* H( ] - else* j8 o# d( \9 r- J7 ~, U# v
- {
* X- t, W! h4 c7 Z( I3 [ - Task.Run(() =>7 Y, n$ j$ D/ m* H% n3 U& P3 o
- {+ E! A, Z! H0 Z& B3 m5 Z7 o
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
( R4 b3 t/ g3 F# | - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
0 {- p: F+ r. E, o" ] - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
7 c* X7 X8 d- S- r8 |2 R - });
2 N; z4 t* j6 R& L" ? - }
4 ]; w$ ^2 W$ v/ z - }
+ G5 }( ?' w1 z' e0 g2 }. E+ _' V. P - catch (Exception exs)+ D. w% N, b6 N# c3 B, I
- {
$ r; G: V1 b9 g5 |+ D: c% c0 X6 | - //消息转发异常处理,本次消息忽略 继续监听接下来的消息& A& P. [. {* U2 p6 k( Z
- }" V0 G, h% _ F/ V( L
- #endregion
$ z* i0 G6 q( ~5 K7 a0 s. } - }! _' R3 _! F3 }& v
- else
7 R ?8 ?6 N0 o e0 Z& s E" g; [ - {
) F6 Y/ }: _ X* l, O k3 x- o5 @ - break;- X, C8 q* G* v# T; v; j
- }
4 m/ U" G% [7 I1 p. [; G4 y6 \ - }//while end
9 w1 z3 U0 P9 N) _% X; Z - }( p- q9 A9 v. }. u
- catch (Exception ex)
. q2 }; \* J+ v" K - {( \/ h% w0 A4 ?7 f: L& T
- //整体异常处理% d* Q! w- N& P/ Q
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
2 N: G* w% x |) }! ^1 @ - }0 r0 e' h. k9 b+ L$ i% J
- }
/ c7 X6 A" U5 C1 K# E! e& w" f
+ o+ Y+ i9 H( a6 N6 [3 O
7 D$ N% b1 D, ~$ r, I- a- public bool IsReusable
! y9 {, F% S! \) J# @: S: W - {2 u: N# `; ~8 D, }
- get& ^/ u( `/ O/ r) W
- {
: s. {: D$ u. L - return false;
7 W6 o. n- r( R4 Y3 J% s - }# X- _+ e# ^5 \) a% i- K
- }+ |) e" m1 h3 x2 t
- }0 U& h; N$ Y: ?1 h4 a% s5 E
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 # C2 F8 a3 h% I' Y) ^
|