|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 # C9 C: o8 ^- C1 D8 m
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;9 H6 p9 o9 B' @9 `+ ^4 ^6 C+ ^, {
- using System.Collections.Generic;
1 e O1 Y- U$ T- U - using System.Linq;; e$ w. e% U, y
- using System.Net.WebSockets;
2 q: U& y0 b! }3 p2 E+ Q - using System.Text;
T9 b5 c+ I8 j; M- [* K' L [ - using System.Threading;
! o" ?$ o& ?9 Q1 X: g0 c - using System.Threading.Tasks;
6 g3 n# j5 g# [6 C0 A - using System.Web;0 f0 q0 d1 C E- O3 ~6 [" u
- using System.Web.WebSockets;
' f, I7 Z f2 b- _% }2 f - ( f8 N: {$ a q8 [6 `& l1 b
3 J# K+ O( D) |8 u6 Q- namespace WebApplicationWebsocketHandler
5 o# Q" }$ V4 G3 ?# y1 T) v% W5 ^ R - {
4 T; R1 `* U* c7 l- }; f# j! ~2 t - /// <summary>$ a+ q' s3 Y3 M- Y$ V' H
- /// 离线消息
% _1 n. k) `+ o/ D2 m+ s - /// </summary>1 e/ R* B# y9 \
- public class MessageInfo
8 ?7 m; o) z9 M2 ~$ D - {
- B( f+ r- ]& n% \; r - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
3 R* v2 ^% O3 a) I3 l2 T - {7 o d. @ a3 m9 m& f
- MsgTime = _MsgTime;% H) k; H1 ?1 s5 l' g3 e
- MsgContent = _MsgContent;
0 M4 q& g N/ d, x - }6 \: R2 \9 I" h2 h* j9 n% i
- public DateTime MsgTime { get; set; }
( s$ ?+ h$ q( j |! d* U* Z+ u0 y - public ArraySegment<byte> MsgContent { get; set; }
5 U7 @. s: |0 m) e5 ]: H - }
- ~ N7 B [& T9 I6 d4 A - 8 S3 G; z, r( ]/ ~) ~! S
3 p% x) B5 e) c0 o% ]" `7 S& ^4 J
% G8 g: B8 E) w. ^: {* ?% W
# m4 W e( `( d6 A- /// <summary>
0 S9 o3 |7 t( z* l - /// Handler1 的摘要说明7 E: E& [ f% {7 t+ K
- /// </summary>6 S% H S: p t0 V4 Y
- public class Handler1 : IHttpHandler
* `1 n0 k1 C: r+ J2 r) O - {. T: R; [4 h& A/ r6 x8 f; s3 ~( l
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
3 A5 p! u2 D# @( t1 _ - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
7 I1 b! O% L: y* d, l. q - public void ProcessRequest(HttpContext context)# r' Z5 n% L( Y7 \" h+ ~7 T- c) l
- {; I H: S J% J3 L! g8 p
- //context.Response.ContentType = "text/plain";
p) E8 d& E. z& Y; Z0 O0 r* Y - //context.Response.Write("Hello World");: } i8 h# G8 b% P8 i
- if (context.IsWebSocketRequest)
- [+ n+ C7 v7 E - {$ s, b$ ?" R1 N. N! u5 e- H
- context.AcceptWebSocketRequest(ProcessChat);
) H4 Q" q8 e( f! y- {0 C - } ; x; K4 ?' y/ H# j
- }
" n0 r, z: ]6 p# V# o( B/ n3 S - % a+ Y4 m8 u0 [$ w
- private async Task ProcessChat(AspNetWebSocketContext context)3 @" s' ~. q/ Z: Z( \
- {
2 Y% {: p) G; l! R8 a. y0 S! z& [& v% ] - WebSocket socket = context.WebSocket;
4 U5 M: h3 X, Y - string user = context.QueryString["user"].ToString();' u/ M% m5 n9 M. }8 b; o
- $ T+ g3 Y- k- h3 t! c' ? R
- try
H" z' V4 y7 h. g# \$ h* _1 z - {7 {" `9 m& u! B- |& }" e2 d
- #region 用户添加连接池: B0 m; F3 W- n) j
- //第一次open时,添加到连接池中% X3 b8 t# D. O
- if (!CONNECT_POOL.ContainsKey(user))+ s- a3 s) o9 U4 r5 A
- CONNECT_POOL.Add(user, socket);//不存在,添加
' @$ C5 i* Q9 q* t( U4 a$ h - else
$ U* k7 t0 U z - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
9 E/ q$ D7 t- l! j - CONNECT_POOL[user] = socket;; C. |) p H. V7 |2 G
- #endregion
: u+ T+ L( }) V i. i - : K3 Z1 `5 c% Q5 h
- #region 离线消息处理9 h$ F. p) t0 Y1 z! | I3 L
- if (MESSAGE_POOL.ContainsKey(user))) f" Q& h% W% }7 c# Z
- {
1 T& Y& \9 L6 | - List<MessageInfo> msgs = MESSAGE_POOL[user];
' Q0 [& c1 B# G2 S+ _$ I - foreach (MessageInfo item in msgs)
" j9 C; A& C$ r1 o$ U% e2 C( z - { Y% c+ k& H( ?7 R% d$ L+ s
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
/ k) B( ?* z4 j% w" @1 U5 V! K - }' Z p3 a; {( X: h
- MESSAGE_POOL.Remove(user);//移除离线消息9 s) V9 H1 G0 P4 s
- }
O& h! R1 p3 { - #endregion5 p% f! E1 _6 `$ I
- # z; I5 g7 Z8 b" `4 d
- string descUser = string.Empty;//目的用户
?5 u/ D, G; x- P4 I* q0 Q" ] - while (true)5 G7 A+ O3 i6 r
- {
' e8 d' ?. T0 Q0 ?6 [9 a* a5 X( p - if (socket.State == WebSocketState.Open)
$ A$ y/ D; ]2 z2 G0 j! a% F - {* K7 r6 P# c" ]; _5 A9 D4 h
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
# C: Y/ Q+ G; d/ u0 k6 { - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);) t% @# s3 e4 O4 i# l) F" c
( a/ _1 ~0 U' L7 _- #region 消息处理(字符截取、消息转发)( V8 [4 q4 @: I) g( b/ ?
- try) R; k4 @. J7 s6 @! N& f
- {
' r) {6 C' X: Z O2 W) \* T$ o - #region 关闭Socket处理,删除连接池7 z1 c5 g2 m# [- L- }0 W
- if (socket.State != WebSocketState.Open)//连接关闭
" E/ e, {/ S1 [: E+ U5 m; W- M& X( w - {
+ m3 l% e% z6 ?7 h W - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池5 Q$ {+ M ]; J. I7 b, y% G) x
- break;
3 l: t% O( a" Q3 k - }+ ?9 u& Q+ g% P/ U# i7 p Q' x) `3 c
- #endregion
0 ?, M3 P* Q" x9 K1 @ - 6 V: V* P2 R# l. s9 }, n# [8 f
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息 f! M* j5 ~1 q7 ]4 |6 V
- string[] msgList = userMsg.Split('|');
6 K( _% O2 p) E; c. [( ] - if (msgList.Length == 2)
& L+ `$ A8 ~. S* j - {
/ S- Y+ H* c! [0 I; ?; _% u - if (msgList[0].Trim().Length > 0)9 `. {- ], G8 M) [8 n
- descUser = msgList[0].Trim();//记录消息目的用户4 T5 a T4 z: \3 P9 r) U
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));1 F* Y/ P# Q O5 ]/ V2 ^1 ~
- }
7 ^1 y# \2 B; c$ D9 ]6 G - else( y; L, Y! D; D* D0 H' A, Q
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
6 X! j6 b; b" z! E5 `% N0 ~8 y
& z, E2 V+ \. v- T7 L5 v& }2 L- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
$ ^+ N! _" U4 r# N - {8 F: ~0 }) y- G
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端$ K# L) R4 H) S1 [$ E
- if (destSocket != null && destSocket.State == WebSocketState.Open)
6 k7 u6 K# \* b - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);7 d |, r; R( ^7 V1 h
- }
3 I% ?3 Y7 F5 `- h A y - else
" Z7 i# G1 V2 f" R! x - {
) k" d2 N Q# w" u; w$ _& d4 X - Task.Run(() =>
; ^1 Z9 O8 e3 j" a$ v - {/ A- u& e! c% h9 Z6 R8 B
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中0 Q" z. r2 J$ ^7 f2 R2 R7 f$ l
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
" J+ _1 l- e9 K* I7 @, y! v, H4 u* e - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息5 `' V2 R! ]# ^- [
- });/ P1 K( z8 g: I
- }
- q/ d3 t* e) ^" n+ p9 J - }
; |7 Z K$ D: w& o - catch (Exception exs)# K* J1 E. D7 L9 b, e) z6 n+ D
- {
' F; A9 D" j+ _2 f; b - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
% ^. P. H# C( L: D* ?5 @ - }
. b+ f! j- D; S3 ]& {/ ^7 n" }' Q - #endregion8 |. i8 U% _: C& k" [' M
- }
/ |7 x" F) s" x/ R - else. i" R& G- ?, l: P! w0 T* l
- {
8 L! |# S9 R5 Y4 o8 F3 L - break;$ s7 _; }! ]* a% W6 {
- }
7 D/ N& o' N0 K' K$ F0 c1 ] - }//while end7 f& d% X m' K9 ^
- }2 C3 I9 w# f! X6 u) k* K
- catch (Exception ex)
1 ?( d2 I" j% N8 @- k" o - {
8 {6 c# H) [$ y - //整体异常处理
( ]# a: |* J# p5 O5 S# q - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);4 K2 D2 k+ z5 z1 u* v& L! O
- }
" q% p& u, c# t( f, I - } M* @: ?' ?# ~) ]
- B$ w$ y$ z8 Q$ C3 a
2 h: x* p3 y1 N+ A- public bool IsReusable6 @4 Z! ~2 P4 P9 H) @
- {
* S6 F6 L; r) m6 `5 z# J - get
* i; V ?+ ^- [5 l - {5 j4 y7 b, ]. }( d- J
- return false;
3 U% R3 q) M$ M$ d$ k( e# ] - }
9 } G! T p! j4 H; a- c5 h - }0 h/ S$ Z3 R, n" j- N- s2 H
- }
, a2 e7 y, S) P9 T3 z - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 ' J) {) Y8 K% y+ N. k
|