|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 ) I1 v& H6 i+ Z6 J
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
! e& ?0 Y. M8 e$ Z, l - using System.Collections.Generic;% A) G/ U$ y4 c, y. J* ?
- using System.Linq;& V) r* g) s/ E$ l: T7 n$ e4 B
- using System.Net.WebSockets;- z: ^2 Y7 T& H% d+ x
- using System.Text;
2 C3 l; Y& G9 A5 B0 x* v - using System.Threading;, G/ M9 u; l+ C* K5 V" L5 z
- using System.Threading.Tasks;. j# W" h+ b1 I: |; V3 l. d
- using System.Web;0 k2 {" i; w% i- k
- using System.Web.WebSockets;
1 g& f s' ~* j4 ~# A9 x - ) `% a3 r. @6 P" n. M; }
! p; p" q+ n& p; Y, Q4 ~- namespace WebApplicationWebsocketHandler9 K1 ^7 r* _8 ], I5 r# [9 @
- {
$ D, ~; J6 s6 x/ |- I* c) q4 N - /// <summary>( p- R B' \+ P' G7 o
- /// 离线消息9 n$ _& X% x5 a J ?; d
- /// </summary>
4 v! i& H/ m' f/ T) U' p - public class MessageInfo+ [) _3 S4 t$ Z8 H) L
- {0 c# Y; H G, S. V: T" C
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)- }$ v/ V0 \% r0 N/ C
- {3 B8 m6 F* A& e5 V) A* G
- MsgTime = _MsgTime;
) Z. S( o' h8 \0 L" F. H6 u- R- e - MsgContent = _MsgContent;
2 V. o0 k* L, X( z5 g) d# Q X - }
% g$ C+ \6 S+ `# N4 T - public DateTime MsgTime { get; set; }
B' |5 q$ H( Y$ M - public ArraySegment<byte> MsgContent { get; set; }
4 Y. y7 Y* }8 x4 ?3 M! Q - }
& I9 E1 H/ G9 ~8 r - * ]- w+ C$ M% F+ m8 h' }
) Z* e$ I3 E& u& B( [- 5 R+ z7 Y6 w# |( Y$ E7 }( A0 m
- ( A: j2 T8 r* T3 {6 {2 C
- /// <summary>
6 e: K2 h9 r6 ^ - /// Handler1 的摘要说明
x3 N/ r( L7 T. ] - /// </summary>
* T+ y+ [" ?# L# Y" ` - public class Handler1 : IHttpHandler5 X9 S: Z' L; [$ z; s8 |# N
- {6 w$ E7 ^, m) `& C4 o. y% Q% t3 C, ^
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池* m4 e, Q9 F# r0 U
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池% c1 a* y( E e r% b
- public void ProcessRequest(HttpContext context)
9 Z2 [8 `0 \1 C! K: I - {
; v" f& `( y* T. R% p$ T" D - //context.Response.ContentType = "text/plain";, s; P! J; m" _5 r4 F
- //context.Response.Write("Hello World");
: i; D$ f5 L) [2 s - if (context.IsWebSocketRequest)+ H0 |# B" M- N* g
- {0 r; \% L( t6 t g& ]/ d4 [9 m
- context.AcceptWebSocketRequest(ProcessChat);: O- ?& s* N. \2 P4 I0 M
- } 5 H+ Z. p! Q1 Y5 E+ s
- }+ [) U H$ q/ ~; ~" F; H) ?' ?
- " y6 V3 v- h0 N
- private async Task ProcessChat(AspNetWebSocketContext context)
; Z7 Y c9 \! c- B3 [& _8 T - {
/ B5 I& Q* ~# l/ \, d# \ - WebSocket socket = context.WebSocket;
0 {! p8 R6 [$ d: o; Y% O - string user = context.QueryString["user"].ToString();& N9 d9 O5 D |" f
/ ~6 D& B) z- F. f; P- try; N( \' @ n& X3 \9 g' t
- {
& r9 D9 ^- n5 P+ U, t+ b7 L - #region 用户添加连接池
8 N* G2 k2 n+ F0 e* |* Q - //第一次open时,添加到连接池中
5 N2 ?- s& {8 x6 {- I - if (!CONNECT_POOL.ContainsKey(user))
$ t0 a: Z) D" }) v* l. P: F - CONNECT_POOL.Add(user, socket);//不存在,添加
3 x6 S" p T, _1 Y! D - else
: H- \% H' U/ z6 e& `3 Y& A - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
9 M" C& T+ C9 h/ @$ M. V - CONNECT_POOL[user] = socket;
9 D! e. K+ B( ?/ o9 g4 M - #endregion
4 ~% R& O7 K) ? - ! |/ F) b1 B, u! P9 u
- #region 离线消息处理
) l; n& F# N5 `: H - if (MESSAGE_POOL.ContainsKey(user))
% g: u3 T9 c9 r& b' e M8 L0 z. ~ - {
7 h8 ?2 \& k, `* K - List<MessageInfo> msgs = MESSAGE_POOL[user];0 x0 Q/ W" I* v: F/ q5 N
- foreach (MessageInfo item in msgs)% G. u; ~$ Q0 q( J! F* |
- {
) G2 l" O& R! Q( }+ ]5 q - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);1 ~% r: Y2 X* [
- }
# m4 i" y7 Y8 E+ { B1 B- j) C - MESSAGE_POOL.Remove(user);//移除离线消息$ }8 ?: E5 i) C4 q3 x: c
- }
/ Z6 Q6 ?. G9 O( p! e' B& Q. M - #endregion. ^ H' q! W1 A! E- u
, H7 S- |2 r* U1 Q$ L- string descUser = string.Empty;//目的用户
% g( U3 j7 E0 ]- o" L- T - while (true)
7 s) ]+ z& @; u- U/ b - {! S1 g; L: V! O. X" n4 l6 ?
- if (socket.State == WebSocketState.Open)
2 b4 y! k7 D% J# P - {5 M6 w' [) v) F, R+ A
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);% b. U" z$ p7 E8 D6 f9 ^+ Y
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);: k. Q. T1 a4 D L# r6 v* t
- % f/ r- B, f2 O
- #region 消息处理(字符截取、消息转发)
- f0 F! ^ S+ M - try
2 ~; ]% Z0 `" }2 s - {$ B- V7 @) q0 _% _6 ?% U% Z
- #region 关闭Socket处理,删除连接池
- l+ x& c! K* h0 S) w! r- R - if (socket.State != WebSocketState.Open)//连接关闭3 f: F! U# I) n) q5 o8 r7 H' `$ b
- {# n! y7 `* t8 n+ ^: E8 x' F/ |
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
6 M4 m+ ?. m; F! K) T- ? - break;
5 Q) a% G4 V. b* d0 ]" j - }: |/ W4 h n9 E# [' a7 i0 V. f. z& |7 p
- #endregion O2 s9 r+ b, c5 s$ `" o2 i
+ q! Z W+ K/ V9 B8 M7 U, S8 x" d2 O- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
* E( m' S# b! I1 K0 n - string[] msgList = userMsg.Split('|');5 N3 l) f- y5 {1 R
- if (msgList.Length == 2)
; W: }% S) Q% E - {' m; F3 H4 i" q1 s+ k
- if (msgList[0].Trim().Length > 0)
$ N: M/ n6 _! H8 B- T+ m7 \ - descUser = msgList[0].Trim();//记录消息目的用户& t# n4 z5 k3 }) O. [1 L
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
+ b2 R4 Z- P+ l( }& z4 W - }
6 h. k; n6 w6 O$ y - else% ]% c% j% l8 f( e$ s0 e
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
, H+ a; v+ U4 ^- [) A
/ n8 ?6 Y# C- b- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线 F, \/ P* t, ~4 c1 R L
- {
/ C: z) P' M7 x% G' l: @- p/ Z - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
, Q3 c) I6 S( c; I$ E, W8 K - if (destSocket != null && destSocket.State == WebSocketState.Open)
; U) c) \9 p4 l' f/ ~& E - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);! z/ w2 Z! t: i2 e2 j
- }2 u2 h% r A% |) C
- else2 G" Y0 t- @7 U5 o. P9 f/ ^
- {* ]3 W) O2 |( d1 B. h
- Task.Run(() =>
/ v: M2 x5 M! ? - {
: J% i' C; H* Z2 }8 ~0 G - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中* w5 ?! a2 _2 X5 r
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());; x y- R) t4 n4 ^: }7 ]
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息2 f8 b' @8 a6 l- @
- });
; m% c' J$ o' Z) c - }! C! [" s8 W: P. c
- }9 a/ _% r$ Y" D; ? I1 O9 X' h
- catch (Exception exs)
$ q+ w' `* [- M- s - {# V$ H1 ?& r0 E7 c8 n
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
4 ^0 y; I8 V! y+ d( M3 y8 N - }
# S2 E p( L( |1 Q - #endregion
" k7 G2 @( Z* b6 C7 H7 v# | - }# B1 N& w! G7 p7 L
- else
0 W* V' I/ j4 D6 l' [ - {& B$ d y8 s9 C: Z' ]
- break;+ M9 _8 q) k* d$ B/ C, n
- }6 A7 {/ s* d; F; [% [) n
- }//while end! }9 K6 y2 X* u4 }) x* G, F& \- k
- }
! t8 f* w1 N4 N# f8 l$ B; M - catch (Exception ex)% H' q& \. V' F4 B$ S' r
- {; n; H9 Y% O' P" Q; v
- //整体异常处理$ s3 ^2 B6 _6 k$ ] f' O9 k
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);0 E0 J' r8 ^) o. l5 t t, x/ A- |
- }
' T/ H' K g3 W! V& ~+ O: y - }! d9 G( Y2 H9 A7 V
- 4 S6 U1 L5 L7 I, ]( n
- ! B8 U4 @0 G0 R" j6 @6 ~' x3 c/ K
- public bool IsReusable" P$ @, t3 a! m" a
- {, E' ]) F& `0 ~& L1 }0 [
- get! G. l8 h* K" m6 a; W l
- {
& v. ?/ B' z: n: L- t% _ O7 t - return false;
7 u% F0 e* k3 g. n - }1 k' K9 D7 ^) z. E
- }! R( Q, a$ z, d3 [
- }
/ m# A, ~* G8 J+ j1 u - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
: Y, W6 @) d+ L2 }- ? |