|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
& @/ ], Z6 Z1 ]9 z7 s7 }2 S- F2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
$ W2 d7 g; k. Q' D - using System.Collections.Generic;
2 \3 K+ X& z2 l. P- x - using System.Linq;! U7 U1 n2 d+ u# {$ ]1 s! d+ I' N, |
- using System.Net.WebSockets;
# k5 W, a6 S3 c8 ^; P! y' P - using System.Text;( Y% Z7 P) r/ }
- using System.Threading;
( G2 g7 l7 h) I9 f" m/ g9 u! D - using System.Threading.Tasks;+ e) y8 R- b. y6 F. \5 A
- using System.Web;
" l. k( o, P8 `2 D$ ]8 H6 X! b# S2 X - using System.Web.WebSockets;
! y) Y2 ]6 ^$ F - " E$ L; R2 h" u* A
! n6 A, w9 c" S! j& Q- namespace WebApplicationWebsocketHandler
1 X5 e0 P1 Y2 `) [ - {
1 Z. A3 C' [% d O - /// <summary>2 e# A9 B+ i' R1 K. w; ^* B# O
- /// 离线消息& n( W; ~4 b' K0 I9 e
- /// </summary>& v U( l2 `- V
- public class MessageInfo- ]1 n0 r1 u6 Q* D& j3 \
- {
, B! q5 V4 o: c( `* Y - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
* B2 X5 C! S! R6 {! v - {$ A- F. P1 N8 Q9 U) `* a
- MsgTime = _MsgTime;* H1 L; ]" _4 D5 |
- MsgContent = _MsgContent;
! m- q$ W6 u7 a/ `8 `3 c s - } u" g% Q6 |6 j
- public DateTime MsgTime { get; set; }
& t1 H M* ]- F. q+ B) P& ]+ a - public ArraySegment<byte> MsgContent { get; set; }
; g" z" _) e' ~" w8 } - }5 F) H5 d" _( V6 p0 `1 a
- # K2 m Q* Q8 |7 y4 l* G$ [8 g" C. ~
8 s4 F# `: \- r3 w% M5 X1 m' f" N0 U
/ m, V; T) W7 [* B$ T$ m$ q
) S: A4 S2 W8 s Y/ ^7 h' d- /// <summary>( v0 s/ w: D: G" G/ h) k( B
- /// Handler1 的摘要说明
- T8 G# e) q% o - /// </summary>
) |3 T& F1 \9 }- S - public class Handler1 : IHttpHandler
2 ~, o3 o# B' r7 u W - {
" D, Z6 B2 g7 r - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池+ j* j" e$ b V T) R
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池- E" C! A, `: r& P2 W( D
- public void ProcessRequest(HttpContext context)5 j6 [# p9 O7 T
- {
7 g3 G0 X% L# J H9 L5 b2 n - //context.Response.ContentType = "text/plain";
. v% j/ r9 N4 u - //context.Response.Write("Hello World");
- f) V8 {% r9 V; |! [ - if (context.IsWebSocketRequest)
. E0 W1 b p0 g0 R1 M, I6 Z2 Q4 p! h4 n - {
" X2 o1 u) j% N- z/ P) a - context.AcceptWebSocketRequest(ProcessChat);
0 T& q3 x" _5 h9 ] i" T - } ) H( Z" z! M: x( U4 V$ x( i6 @
- }
2 W! \5 i0 m$ K - 8 K# c% I% T. U8 W+ e
- private async Task ProcessChat(AspNetWebSocketContext context)+ |5 R j" r& n/ q0 ]. L
- {( @ Y1 ^$ {' _, {3 o7 h
- WebSocket socket = context.WebSocket;
8 U& L* r z% D+ t9 G5 ~: ? - string user = context.QueryString["user"].ToString();
7 ^( e- L" L/ |8 `- e. v; \3 e - ! }) \0 h e+ F
- try# H3 F7 L) b# Q& V
- {
+ u# ]3 l& o) f6 T - #region 用户添加连接池
- v+ b. Y) ^$ i' p1 _: Q( X. v - //第一次open时,添加到连接池中8 D. i0 X9 l, H& |1 N! d5 I
- if (!CONNECT_POOL.ContainsKey(user)), z$ J% L' Y" r$ p3 I
- CONNECT_POOL.Add(user, socket);//不存在,添加
) X5 T3 z2 s8 ]2 n! ?1 M5 | - else3 R% z" Y. T' D/ ~
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
9 ]# J5 z8 V6 A - CONNECT_POOL[user] = socket;; }% B, ~9 A' t9 m- X
- #endregion6 |. e, s1 h+ Y/ l0 y4 C
- . w4 U: a, O* l; r) s- D6 I8 g" e
- #region 离线消息处理
6 L5 b" k( R& O d5 v - if (MESSAGE_POOL.ContainsKey(user))% ~8 f; x4 e) m" v3 C
- {
$ [8 ] c% y8 A - List<MessageInfo> msgs = MESSAGE_POOL[user];
3 |* J& \/ _+ }( y8 ~& [" s - foreach (MessageInfo item in msgs)
; Q5 v. q9 X, a' g5 S: E: ^5 [ - {
" A, H. G+ F( \6 F% t. Z - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);0 M& \1 z( f1 U I% K2 W
- }
2 Y5 _, _1 }) l% D - MESSAGE_POOL.Remove(user);//移除离线消息, k- ~/ `3 f+ Q, I
- }- i# @- W6 F2 p) K0 b: j2 M( s
- #endregion
$ Q- k1 b n. a: s- ?. B5 l0 b7 L - " c- |+ b9 A) W) w! i8 _
- string descUser = string.Empty;//目的用户
! V5 Y. ]5 L5 x$ }) v! a$ m - while (true)3 F+ _; Q& ~1 t$ } {% ^$ Z9 B
- {) P# o! ?" V; P3 x
- if (socket.State == WebSocketState.Open)8 c+ K. h- T3 O
- {/ L. ~4 a% g7 v: r2 N7 a
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);8 @& y! z' e7 j( ?7 ?5 G6 c" b9 Y
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);" R" U: N7 f' e6 f$ w
- 1 I9 z4 r; z) B- a U3 Q
- #region 消息处理(字符截取、消息转发)
" K: j1 A2 S) V( j. J0 u6 Y - try9 F( A/ L/ f3 ]# i; a/ t1 Y
- {0 R. y0 \" Z8 K/ E# J
- #region 关闭Socket处理,删除连接池 y9 P. @0 @) N5 G) ~" J) G
- if (socket.State != WebSocketState.Open)//连接关闭
- m+ o8 E: \3 r9 G, z5 l - {
0 ^. O% {, E5 R, C - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池( l% k- x6 x5 C) G: G
- break;
, p0 Q W7 e( K7 v; W, r* D0 M# m2 Q - }1 l9 U z2 G' o7 ]- B/ U
- #endregion
* ? O; R8 k, o# i: ^9 o+ D' P5 ~ - 8 e5 T1 w3 n$ R* r$ s0 O$ v
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息2 _; z" {" ]2 d4 a+ C) O6 U, E
- string[] msgList = userMsg.Split('|');
1 T8 m: Y0 r# f- g - if (msgList.Length == 2)
, F( R% R, E5 L% ~# E - {
4 z2 }- l, f1 O! R2 @2 P2 X B - if (msgList[0].Trim().Length > 0)
& ~# c. w! H+ h1 R! [ - descUser = msgList[0].Trim();//记录消息目的用户4 J* C2 U6 K- U `8 \$ |
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
. w S+ G! p- i1 [ - }+ w, a9 t0 R" d* G7 ]4 v
- else' b. u$ r& r3 N/ K, O# I9 n) }) Q
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
, x+ \! t2 B" O- @0 K* t& n
: }$ [' w' p4 y1 b8 Z5 d1 j- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线" n: u7 }$ @$ M0 Z* g7 ?
- {! ^: N6 L# @! i+ L# ~
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
) @& K+ @( [, Q( N w7 w. J$ U - if (destSocket != null && destSocket.State == WebSocketState.Open)
: c4 X! o5 i' [7 A3 L& o2 {2 ` - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);5 C* n( |- V" y9 p& U
- }
! W1 ?' \& ] B* U - else
/ W- t2 |7 v! P% t; h' i/ u - {
7 h, A, t5 A L) ^3 ^. |" C0 T - Task.Run(() =>
. J! F$ v$ d' X6 I - {
7 \" }) ?! ]- f - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
" ?" ^% U4 h7 G! g8 ^ - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
% X7 i8 n/ U3 r4 \" n; |* T - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
( N$ i, Q! f& p& c - });
, S; B0 k9 N, N; s; i! `6 w2 I! R - }
+ P/ W3 G- d: t. v8 O" {' h - }; o% z2 R* T* n6 h2 C
- catch (Exception exs)' ]5 R) Z$ H2 O7 q' _. T
- {
4 q0 T1 w; E4 `9 D - //消息转发异常处理,本次消息忽略 继续监听接下来的消息' v, L/ W3 S3 {6 `" L& V4 G
- }& o6 n& S& }4 z, D
- #endregion
# g% j _& ]' t# |" m - }
8 O! M9 Q. T& N0 B, }8 f) v - else/ G& L& }1 ]& A* U; n( ]
- {* A8 i/ G+ C6 G% s9 M2 C ~& d0 X7 t
- break;
% Y/ r1 b$ ` y% `- Q0 D* c: X. y - }
# |! I5 z& Z( U( M Q - }//while end
) b+ D6 x* P4 A5 \$ C0 N3 y6 @8 G - }
* s- R- r+ p. c- F9 z+ z2 r, N - catch (Exception ex)
. s6 v) A5 J& F$ v2 l5 ]/ i6 x - {8 d' d- [ v$ @4 r0 e: \' i
- //整体异常处理 F" |- j8 v& O2 D# A
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);4 y0 }* h' U3 J1 w) o
- }
. Y; B$ g- k! B: }' J - }; C. I2 h7 K, L" P
- % G# S; K& [2 \" P, x; U1 y) `
7 _) e a5 `7 s4 u9 x: f8 c/ P: k- public bool IsReusable
# m1 b, h) H9 f8 M: G9 |4 W - {
# c. F/ \% r/ e4 i: ?; }" X - get2 |* c3 X7 P# e% h' a( U7 W- C
- {" } T0 J: G- r% a
- return false;2 K& V1 J# R. V- c
- }. i$ }5 [6 E4 y! ], a: l
- }
* \! f' V/ ^+ }, p/ K3 f - }
0 I: Z" v; l- N) L t - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
) O8 J; ]- R& u0 s! s- R9 w |