|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
; }: M t$ D. ]7 M; H: f3 y2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;9 `( U7 g, q9 Z& d/ s0 ^ K" l
- using System.Collections.Generic;
& H6 M. E' D5 Z x9 F3 ^ - using System.Linq;
8 ^& h( U0 u" x: {6 S - using System.Net.WebSockets;9 x' B; d/ Z, M& t! s' V& ]( x
- using System.Text;
+ R3 R! ^% Y, d- f! ~ - using System.Threading;: r! h/ b5 P; v
- using System.Threading.Tasks;
K9 a, T9 o: m( \4 O - using System.Web;: T" T' h' m/ o! \
- using System.Web.WebSockets;
/ C+ e# t& g; D8 `; R
2 B# Q% |, V5 d" Q" r/ X- 4 T j$ l- U5 M" a2 d9 J
- namespace WebApplicationWebsocketHandler7 j& o3 r g4 E \
- {* E6 i. s( }) B
- /// <summary>) B) W: J7 k0 @( X i1 O, F( R3 l0 z
- /// 离线消息
% i5 W0 M( ^ Y* h - /// </summary>
$ l! u) D3 ~7 x# H: ] - public class MessageInfo
! p! E' M3 Y; c( W: ^ - {4 r0 p4 z( q. W! x8 w/ Z. K1 u W
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)* m! {7 G A, U) g' i% N5 x
- {, ^% r: b1 S# X$ r5 i) A0 ?% x+ v
- MsgTime = _MsgTime;
% }, n/ _& h) M) s - MsgContent = _MsgContent;* l3 V2 X$ ?, Z4 y
- }
( U$ S% T7 Q z% h& G2 s - public DateTime MsgTime { get; set; }: P# [& z/ @/ [+ q) |. E
- public ArraySegment<byte> MsgContent { get; set; }% i3 ^1 ]6 x5 h- T( Z
- }1 Z3 }$ |# K3 C/ B* E
- 0 w7 c2 @4 M( E7 `, R
& @$ }" d0 }& v6 X0 Q9 s o4 [/ [
' }; P( u! S( O a2 r
' }4 ~2 A4 R/ s- /// <summary>
9 L& w' m8 Q7 O- ^' s - /// Handler1 的摘要说明
% W/ S* W2 Q) b% o0 S6 q0 C6 h - /// </summary>
& X3 ?' G5 y8 r, m, [ - public class Handler1 : IHttpHandler3 T, ~# W0 P( `: k( \, v" ^ F
- {: @! t- @/ a* e& ]
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池; a" u* T9 P9 E8 L) P# |
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池3 T% i4 b5 }- d1 j, G+ v1 n! Z0 Y1 J
- public void ProcessRequest(HttpContext context)) Q! y, i+ i& w! ~; j0 b
- {
. W8 X1 @+ U" ? - //context.Response.ContentType = "text/plain";
; m& h8 I: _( b; j8 S - //context.Response.Write("Hello World");
1 p, B+ h* `' x - if (context.IsWebSocketRequest). P& E5 Y$ X6 i w3 |8 y, }; Y) X
- {
: l, |0 n+ E4 Q; D - context.AcceptWebSocketRequest(ProcessChat);3 W* u$ [+ f6 o- O M, e& z3 p. |
- } - Q, c3 T9 ~( y2 j& _" L
- }- h+ O8 A, r7 |9 T4 b$ Y% z
- 1 Q p1 J* b3 h6 E) _
- private async Task ProcessChat(AspNetWebSocketContext context)
+ ]8 r/ F, B% e- U. g+ A; M# Q& Q - {" D4 K3 r& s% N9 ]
- WebSocket socket = context.WebSocket;
# G/ H" N+ C- D$ o, W" n" U6 T - string user = context.QueryString["user"].ToString();. A' o& V3 C$ v4 z' y; ? p! x
- 9 I: v& g; c/ R# e+ U( ^8 D$ A" M
- try; W0 W& a; S1 e1 ^6 m5 s
- {: o- r/ k6 ]9 `8 F' n' N; n! `
- #region 用户添加连接池
9 L- Z* e" [, h7 @. O4 c - //第一次open时,添加到连接池中7 d$ p! C- L" y' L
- if (!CONNECT_POOL.ContainsKey(user))/ m) c8 J& K* y3 u
- CONNECT_POOL.Add(user, socket);//不存在,添加
3 u* a) e: K7 u |! L - else w; }! g. h) P. G0 t: q! z3 Q/ k
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新% O# G" R' Q6 ]8 n/ T, f/ a
- CONNECT_POOL[user] = socket;
7 u- K0 i* P$ X% C - #endregion5 m5 y( b2 C6 A$ ~/ \0 [; z
- / W* K* S' a. ^# p0 y4 Y: O ]
- #region 离线消息处理8 r& c# T. c2 a
- if (MESSAGE_POOL.ContainsKey(user))
* M. a0 U8 Y# ~* ^: y - {
% o0 d$ ^% f& K$ A" P' W& @ - List<MessageInfo> msgs = MESSAGE_POOL[user];% b( W" R7 j. G/ h& q7 f1 G2 X' ~+ ?
- foreach (MessageInfo item in msgs)
: J) M0 w. ]% X - {
2 i* k" `' y0 S) Q P8 f0 f# ]/ B - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None); X3 ~' @: U% M9 ^0 d# e0 w4 ^
- }* z3 R0 Y5 M2 j5 }" {+ {( W0 L4 M
- MESSAGE_POOL.Remove(user);//移除离线消息
# u' w' @: J! d) J0 ~! b - }$ W4 W4 Y% c$ H% b/ M7 L2 R4 O
- #endregion- {0 Q* g$ ]& l* e- j0 a
' C; Y# m0 e# u/ D- string descUser = string.Empty;//目的用户: ], f" f: M: d) m
- while (true)
# A0 y' T3 T- O# H; x* s - {+ r2 x1 f8 w2 t0 S, E3 L! f
- if (socket.State == WebSocketState.Open)
. ^( R7 D) j1 c/ n- o - {
, A' x. K; S& ]6 Z - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);5 Q$ x i( B6 n$ w
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);3 c$ j3 l% x& j0 M
, f9 a B% V# c E- #region 消息处理(字符截取、消息转发)$ l7 q) P( m3 b1 Q# [6 b7 r
- try% [6 A7 r# r/ Q: g& ~# J; f+ `
- {
: C$ I0 Y2 }: P! k& _4 @ - #region 关闭Socket处理,删除连接池' W1 |- `: N9 M) X" _
- if (socket.State != WebSocketState.Open)//连接关闭& O; G3 `; ^ A: j2 W4 v f: G, f
- {- ^) S+ ~% y3 ]9 d! q k, i/ r+ o
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
: n' C: ~% W) @' O' L5 X* c W9 O - break;5 n5 U" K4 G( W7 J
- }
1 f) |! Y1 X% } ?/ `# L - #endregion3 M! Y% H6 n. b$ c; {- @
9 T& O. D/ J3 c- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
( z; w; g( K2 f - string[] msgList = userMsg.Split('|');7 g, h2 e3 }+ i4 ~: ~- e
- if (msgList.Length == 2)
, O5 H) ~0 Y! V8 _$ p. P - {
- _( t, D' I) R! ?. I - if (msgList[0].Trim().Length > 0)
3 P" K3 h1 w P/ f& Y8 X4 a- c9 v - descUser = msgList[0].Trim();//记录消息目的用户# C" R7 t/ Y1 O5 X; D
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
' X3 [7 n' j8 ]5 f& v2 F- l( E - }
' E1 }( y# u% P4 x - else1 [- Q+ y+ W) p/ E1 i0 k/ s
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));8 ?; ~2 w) g, n1 l; D- S4 W
- ! x( s' V, a. f0 G9 i( R1 H
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线( B" `6 N- K% w
- {- u7 ]4 @$ T; l. e# n' M
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
3 |; }% \& R _2 w" n - if (destSocket != null && destSocket.State == WebSocketState.Open)
4 r- m. c; v7 L$ j/ {! i - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);9 ~% z" {6 a' @
- }
2 @$ C7 ?3 V9 {" z& D4 c - else
0 I% ?: i0 K. t4 D0 [" {- J7 d - {8 Q) t1 h9 t: h1 L9 M
- Task.Run(() =>% ^8 w, F, _" N
- {4 W. ]# g' Y7 n- P8 G4 S
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中/ {1 |! o1 H; J6 r( M
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
/ a _1 k) \' f: a% c3 e - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
6 e. a# H+ u) \, P - });
6 u# q! x+ O, P0 W+ V0 Z: l9 ] - }+ Z! A7 [$ m* k$ L" A! n
- }
; L7 e- x; S. b0 U" C# I# u - catch (Exception exs)) Z' ]7 V r* E& \
- {0 b5 o5 ]% ^: E0 }3 q3 K
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
$ n5 p* e* l! B1 t$ H - }
+ Q+ r: S s! v3 n( p/ v& N - #endregion* X" Y) j8 w; I, c. N, ^8 S1 e
- }! S. P3 \! S, W
- else/ u$ y* i; H: U9 p" {
- {
: f. T& S; d& U) c - break;5 Y( W( i9 _# S' b5 p& ?
- }
. q* h) J% O- V4 S7 b - }//while end {* e( ?3 B: i/ _5 N. s4 Q
- }
7 w( u5 r0 b' `8 R# ^0 b - catch (Exception ex)
1 a3 n0 I' l3 r" i- s - {
/ h6 A. z( A1 N8 _ - //整体异常处理& n4 T2 Q. d3 I& k3 j) ~
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
. S) X3 N8 W. ?; U5 q; u2 g - }
3 i. E4 k; _; s1 K1 p5 g c) E, C - }$ j- N. d2 y* a3 f" x+ G
' d! \- N4 [/ j+ L- S
: {! A2 z& {" S8 h |+ X( R& p- public bool IsReusable+ L; Q7 g& o' X4 E, N% `
- {. r' E8 s7 t# r
- get2 N/ U; n# w0 y6 ]
- {
# |, s, k, m6 b5 e* Y1 ~ - return false;2 z/ A4 N& b% C
- }
[2 F$ K2 b) X - }
& P5 v1 n' X0 L9 a! M3 O - }! M/ Z/ o. d9 H `
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
, x" R1 ~* e3 j* s& j6 y( h- ? |