|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
1 r+ l" k, l' l% Y2 E2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
. m: E/ o9 y# x6 E3 p; M8 v4 O4 {8 o - using System.Collections.Generic;* j# d9 S, y }: T/ p
- using System.Linq;
7 r3 s4 z8 [! }- P5 u( a - using System.Net.WebSockets;. D% \" k# l& k8 D+ o
- using System.Text;
- T: Q4 n9 h/ d* R/ F5 } - using System.Threading;
. V* ^9 w' `( ^8 k' g7 I3 j" R+ X - using System.Threading.Tasks;
2 q. x) f5 _6 f1 k - using System.Web;
( p% H/ _0 b8 P _5 t' P) c; e4 C1 n9 } - using System.Web.WebSockets;
4 Q2 q( I2 s) Q - J/ o; t/ H( c6 Q7 j$ n& A- P% I. V
1 c: L' _/ J# }3 i% W3 f- namespace WebApplicationWebsocketHandler3 G4 n- z; M! w N
- {1 t$ q6 L; K) `, c8 u3 D
- /// <summary>
% V6 X$ M2 H& f, P" V - /// 离线消息
0 T7 }* r) @" X - /// </summary>+ Y6 {; @" k" i: ^( D
- public class MessageInfo
/ v% b1 z; ^5 z7 D6 G) T - {5 o$ m7 E/ m8 d
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
; g9 k1 _% c7 z4 N6 _) ~ - {
1 g P( K4 g" x. @( }. C$ c- v - MsgTime = _MsgTime;
5 s& y' h' P* }; k - MsgContent = _MsgContent;
5 s4 b! |" i5 L2 `9 ?1 | - }: O) d2 o: @# F. C y n) ?
- public DateTime MsgTime { get; set; }9 i$ J: ^, N# Q
- public ArraySegment<byte> MsgContent { get; set; }
3 ?$ Z- V V) w5 B. P - }
/ g% V9 o1 J9 Y$ ]; V4 {# d: |/ x - 0 _: ?* `" G9 s- a$ S9 F" F
- # Z6 K* {' k7 G$ v" |8 g/ } L
- ) [- g1 O3 m7 ]3 `0 |8 ?5 ^+ E7 N) D
8 j+ [- \4 F$ O0 {- /// <summary>; t; s/ { a- e) V7 E5 L' u5 j3 g
- /// Handler1 的摘要说明
+ W k: w! P7 T g1 g& n - /// </summary>3 U3 d) Z! W4 D9 F
- public class Handler1 : IHttpHandler+ @) Q2 p- F9 G. z
- {. |3 C$ [! h1 X* `4 R! e: x7 B- c- f
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
8 V, C. X5 \% d+ c0 F - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池1 u4 B5 v( R% V' s( B; p$ g; C L4 }
- public void ProcessRequest(HttpContext context)
8 D. c6 ]- f: B8 u - {) W' P/ I$ N) i4 u( H3 P
- //context.Response.ContentType = "text/plain";
# g, G+ R V0 H- Z - //context.Response.Write("Hello World");% H; @) r: P3 t7 P. k- @
- if (context.IsWebSocketRequest) l7 v! N4 L: w s
- {
4 D/ H6 e& _0 V1 a' r" N) [ - context.AcceptWebSocketRequest(ProcessChat);9 ^- |6 g! F2 {3 D
- }
' h. S$ {7 {3 A* w! `% @ - }% k$ N' v% ]3 x( I: o& V
- $ u0 P% }, A/ [( t
- private async Task ProcessChat(AspNetWebSocketContext context)- E7 R& g: G& O/ C
- {
6 M# f5 i, o+ Z& p8 l - WebSocket socket = context.WebSocket;/ e' Z# p8 n3 e
- string user = context.QueryString["user"].ToString();) G/ B1 }% l1 S: ?
- 1 F* X5 a$ n$ i# J
- try, M% F$ q4 S. Y- K
- {
1 D' | t7 ^/ [: p - #region 用户添加连接池2 O7 u! Z1 @5 F' Z6 y* s4 [
- //第一次open时,添加到连接池中 _8 u. Y% q; i
- if (!CONNECT_POOL.ContainsKey(user)): J9 x- v* N" a2 q0 R, @
- CONNECT_POOL.Add(user, socket);//不存在,添加7 }$ Z i& ^ |' X9 b5 e
- else8 E# ^5 e+ }; Q0 D
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
' K9 X& [0 v7 u5 M0 C# |, n - CONNECT_POOL[user] = socket;( d A" a; |% a" N' L* K" c
- #endregion" C* B- U# R! R' e X7 D
/ q" f& X F# f- #region 离线消息处理& f& G. k( n9 m! }' V# r
- if (MESSAGE_POOL.ContainsKey(user)). h6 e M7 O+ n/ u' M/ o
- {) V0 m# \3 X$ q% ~! R/ X( c1 ]! @
- List<MessageInfo> msgs = MESSAGE_POOL[user];
: q: o! O9 [* j% j - foreach (MessageInfo item in msgs)" C* }2 E* s; {/ a) }+ n
- {% l+ E* |) }5 Q
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
4 n& Q5 z) S6 x - }
- [! M5 k6 N+ K7 s - MESSAGE_POOL.Remove(user);//移除离线消息; z8 I+ K w- b8 }$ a/ p' Z t3 r$ Y
- }' D! }" ?& K8 A/ r9 U/ ]
- #endregion, c9 h0 r( f) y" Q$ B
- 4 d9 G# J( | ^3 c4 b1 x
- string descUser = string.Empty;//目的用户& u& r6 t6 t9 H4 l$ ~* m) K! t
- while (true)4 Z6 v9 L, H2 P" T1 H
- {
5 E& s, d% b7 R: Q ?) w. Y( _ - if (socket.State == WebSocketState.Open)
% U; l; k9 K( N A& ` u - {/ i' C R; D. a- O0 V8 T7 Q* P( S
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
1 j. e" K6 N( r, e2 F3 {, M - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);3 E4 p& d$ u) x0 P& V* ~3 ?
- ! ^7 y% J2 g$ E$ u. o4 f
- #region 消息处理(字符截取、消息转发)
4 }% r, v; p% o1 G- @3 |2 w - try* C& V7 l" X0 F: z& |
- {
$ r1 g1 B5 C. T* b, i) X - #region 关闭Socket处理,删除连接池
! I! a+ }" x- w: J0 Y - if (socket.State != WebSocketState.Open)//连接关闭, G, a, L$ l/ z
- {3 n; z: t( Z# }. ^) X! P% m
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
4 c( n- ~) Z; w; e: e4 X - break;! F7 H1 Z% ^" }" ^' q+ r
- }
8 ]/ X& n2 r+ X: v& v7 S - #endregion
& r" S/ p1 W; Q( u0 w# H
0 J7 J2 [% D3 D3 ^4 B4 C) U- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息5 q6 I- B( i8 p* u
- string[] msgList = userMsg.Split('|'); [/ c. Z& g# n$ A, \- Y5 A3 r
- if (msgList.Length == 2)
6 i+ L5 d4 p- ?; s - {( a# Z- q7 ]" l4 r1 B! o
- if (msgList[0].Trim().Length > 0)9 c6 { c6 o) ^- i1 b' c% A
- descUser = msgList[0].Trim();//记录消息目的用户
( D; `& b7 f0 z7 @) J$ [# s - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));6 }; ^- m& G8 P- _. _6 k
- }
7 N0 T. \6 u; P% q' o, h+ [* Z - else
, e* K) D: Z" n) j% H - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));0 }% f& ?. F* u( I
- ! m0 `$ h7 f. M) w# b% l i
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线. J' Z6 @7 l! Q% V6 }
- {
+ x0 m/ z0 ?; x0 \% X - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端! `, \+ u% e) ^5 t' r# f
- if (destSocket != null && destSocket.State == WebSocketState.Open)4 n% h9 |9 W% R) G0 c
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);0 A: {5 g& s* ]; T
- }
' A6 t+ x/ W& R: ~9 w - else
1 g6 a( `" b5 j6 B$ k( {" w; u - {. b1 T. m: A5 q- A: C
- Task.Run(() =>$ X# A9 [- M% [4 e9 }, q5 c
- {
. h G; N2 u: _3 x. }2 N3 q/ F - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
- W5 w% K5 h, j# W9 t - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
5 t( ? c& _+ e - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
$ X# `( p, ]) V2 g+ e8 { - });1 f3 d/ K# ^# s9 r6 G& r
- }
: @) R; y/ \! L1 R( Y* v; t3 ]; d - }0 d6 |' \; S8 M
- catch (Exception exs)+ J, ?0 ^, Q: g7 o8 @
- {! R# v4 T4 N5 M* R
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息/ w3 D( A! I. m; p
- }
" c! W5 f4 V+ ]' o$ p - #endregion
% i* D0 [9 Z5 Q3 }6 i- Z, R - }
7 v& L4 T- K; G" j# I, W) L# x - else
4 b. v s$ Z# i( ^# R - {# X3 I0 l' l; P4 w) L% i
- break;1 i; V6 A1 A* e* M4 \% ?* }/ ?9 ?
- }$ a; d, ~- n3 S/ t! {
- }//while end# k# x3 X7 T9 ~8 I/ Y
- }* U* q3 H) J, h I
- catch (Exception ex)6 `: ?6 {" p6 `8 h0 i+ ]
- {
5 r( X/ q3 s* V+ U5 s - //整体异常处理9 Q8 u# |* v6 Q0 B; i
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);" V! v5 f) A) G& y+ j9 \% t
- }. n- M+ v( Y8 h5 \' v; s% ~( S
- }
5 M4 c7 F1 G- A9 N+ m) b
- F, Q$ h' ]8 W6 ` Y8 Y0 d- - ]/ l9 W7 I. p) k- E$ E5 R7 ^+ i
- public bool IsReusable
" c/ ^3 _2 G' ~& j% k - {# H @7 y7 |* F
- get/ r3 l8 l# L7 k( m! @6 t
- {$ E$ O9 h- u5 E! o
- return false;
4 H/ T% n# o0 u0 M2 q. ^5 f; _2 u9 B - }
4 t$ o# D6 f: B' R - }
. U8 x& c7 C5 r" w, A - }8 W- o) K' O+ x
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
- S: w* p6 Z' H h |