|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 ! y' A6 C0 B/ A2 k4 @
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;# ^% o5 b! Y( [8 _( g7 I- @$ S
- using System.Collections.Generic;. N' Z w' b8 U# p1 \* W+ K) z0 I
- using System.Linq;4 H0 Q+ q+ x$ z1 f2 W
- using System.Net.WebSockets;; M% B0 A: b/ x \1 j/ A) C F
- using System.Text;% s6 Y- e) n& L
- using System.Threading;
0 e* t/ Z6 B- L. v. H - using System.Threading.Tasks;
3 [2 e# I6 R( O. e$ w - using System.Web;$ f0 h( t' m" ^; n1 N! f k
- using System.Web.WebSockets;) D1 y5 M3 ~" f" w$ X+ e, P. B7 {
) M; l- t. M& B, j
& G1 |8 ?% Q1 T, |- namespace WebApplicationWebsocketHandler, x. V8 j) S! K4 V" d* y
- {
* r" w9 q% x) Y5 q( D. X* o5 ]/ n - /// <summary>6 f9 \! Y4 @- B. j9 _. J
- /// 离线消息- `; n8 G2 k1 u( O
- /// </summary>1 \0 n: v" J# q8 y5 d
- public class MessageInfo
" f' S: {+ r; i - {
: x+ }9 p& c# c' L: L - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)) s! E1 T* p+ {1 I
- {3 i. b& _, ? C. r
- MsgTime = _MsgTime; l* F0 J) p4 V! m
- MsgContent = _MsgContent;
2 ~/ m6 s; I+ E: r) p3 E" t7 | - }
6 {* d8 Z1 @- ^1 u+ V, k& J - public DateTime MsgTime { get; set; }
3 L2 o" e! J1 m' p - public ArraySegment<byte> MsgContent { get; set; }
7 F4 _ X0 O2 P- F9 B" o - }* J; b. P( S: M% m, p! j3 K
) [" C& Q: [* T( x- : L+ S/ H3 N2 K7 V0 U& F, Y5 m/ A, s
- ( j1 j! d* {9 Z5 d$ V$ I
- " w, |- V, ^. j4 v. @
- /// <summary>6 x0 W# \1 e- F4 X7 n; n. k! e/ }
- /// Handler1 的摘要说明$ b. C: U" b+ k
- /// </summary>
+ F' y0 T7 n8 {$ c3 t7 d( F - public class Handler1 : IHttpHandler
6 D$ v$ B/ L5 m, l9 R5 n% T, A+ ? - {
; F. r( o) }& T( c - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池+ T8 S0 a. j5 D7 S' B7 x$ v6 s: }
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池+ ]# V; a+ @3 N9 [2 ^2 K0 g
- public void ProcessRequest(HttpContext context)9 {" j( T- b5 u7 h
- {* l' u9 ]! ~" n1 v% R6 j7 b
- //context.Response.ContentType = "text/plain";: C8 L6 y7 I% ?1 \0 g
- //context.Response.Write("Hello World");
+ h6 k- ^4 A% m1 j1 {9 C - if (context.IsWebSocketRequest)8 B& m8 H) T X$ h+ Z) i
- {
4 [5 K( N9 s0 @1 k! s" }5 c - context.AcceptWebSocketRequest(ProcessChat);# z3 F ]6 G, }8 @0 \- [
- } 8 V2 V& n% A, \) n! F/ G! p f
- }3 f) o; E7 A) l- j' h/ P
4 X# w3 X- H: E# ?+ N- private async Task ProcessChat(AspNetWebSocketContext context)
; K' c" q; U5 y- ]% \: k4 Z7 o - {
4 ]. @8 u3 p8 B' P# S0 V5 @ - WebSocket socket = context.WebSocket;
5 Y) G( N- e, _; q5 Q4 J- y - string user = context.QueryString["user"].ToString();7 q2 P: \# f. a$ u8 b' e: |0 V
+ W: A3 f* z# g* [ R- try! L' Y; q# {" ^: t
- {
, ?) p: T& }- P& [' U: x7 W - #region 用户添加连接池1 B! p# o7 M% x1 z# ^3 ~9 K3 R
- //第一次open时,添加到连接池中
. G1 q x4 m; V* G3 V8 e) d. } - if (!CONNECT_POOL.ContainsKey(user))( P6 P8 y9 R$ z3 d
- CONNECT_POOL.Add(user, socket);//不存在,添加
+ G( b0 B X6 d7 M. t - else7 [! o. E% x0 B( n/ z- B
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新0 f) q+ k& \3 S' d
- CONNECT_POOL[user] = socket;# @$ Y3 e9 t+ v) u3 `6 o* p X
- #endregion( ^. V- ]) X% S* @$ H! k1 l5 x
- 7 o5 X/ p7 g) h$ c8 L
- #region 离线消息处理
s$ ?. W- e, A2 P. n: k - if (MESSAGE_POOL.ContainsKey(user))
7 @* w" a$ ?) q" H9 k+ q8 I - {2 z8 R& Q# W* }) Y5 w( F. b Q
- List<MessageInfo> msgs = MESSAGE_POOL[user];
! u8 u# A- k' j+ B- |: \- j9 \1 [ - foreach (MessageInfo item in msgs)
/ L" `2 q2 B, L i; n5 v - {
2 x. }9 L5 h% n$ e% a; F - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
/ }- g/ O, J' h3 f$ L; F; C# L7 [( M - }/ L c/ H7 w1 v: M4 t9 D
- MESSAGE_POOL.Remove(user);//移除离线消息
6 {8 S1 b* w+ X! f1 S% { - }
$ g8 P8 Q8 P& W$ |( _, q9 z - #endregion T" T0 S* w, ~4 \/ {: |, N& j' b2 j
- # r9 x& x' y: k P; @% ]+ N" A' W0 c3 H
- string descUser = string.Empty;//目的用户
; Q3 P2 P: d% Z, n - while (true)
/ w+ ?6 r" O; v1 k) Q- Q, P - {
$ I1 D4 c& ~# z5 c; ^, C' c - if (socket.State == WebSocketState.Open)0 Z, [3 F1 _$ I- j# {$ P
- {
0 N$ D5 X0 _5 d! `2 } - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);: q8 \$ g% M' L+ F) R
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);+ T$ b& d4 R8 q5 J
- / a" @ D% J8 ?( @7 a3 H! G7 M; h7 h
- #region 消息处理(字符截取、消息转发)4 b* X6 s6 y6 [/ X- b. P6 \
- try& I* k- E1 o) p' o t* s
- {
$ B+ n# s4 w) \% X9 l& X - #region 关闭Socket处理,删除连接池. ?) J7 q8 u3 n7 B
- if (socket.State != WebSocketState.Open)//连接关闭7 T' u; m i5 @) J3 `( K
- {
7 y4 L2 j A0 C1 x - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池2 [( ?; o: I7 h1 e
- break;3 O$ Y$ V0 X% e. k$ O
- }% {# e, y) @; l" [
- #endregion
) w- u1 o6 a0 e, f* Q
. k: W0 ~: f: ]/ H2 |: z- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息: X6 [- b( u" w; w
- string[] msgList = userMsg.Split('|');
5 s( D$ a3 ~! _' j4 H: S/ F' d - if (msgList.Length == 2)- {' _9 C$ p/ a1 Z) T+ K# c4 J
- {+ b5 O4 K+ f, C' u$ l
- if (msgList[0].Trim().Length > 0)
& l# I7 _4 j) R$ s. W) } - descUser = msgList[0].Trim();//记录消息目的用户
" C- E: T9 t. M" ] Q$ v/ z s - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
: O0 B+ {: f& Z/ i* @) S - }* p* B p- X% A7 @3 D: E% x
- else, n* X. p f0 x' u" ^- ]
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
/ w" t8 E- M' [ - % o& F& v( A% q; ~8 T O
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
1 u2 C! b: ]2 Z- z G - {
+ C9 v- J* ?& K" B - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端' |5 {4 m0 [8 ]
- if (destSocket != null && destSocket.State == WebSocketState.Open)
! }' A+ G$ p3 t2 l G9 ? - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);0 f2 E0 m/ C2 c" y/ o: j$ H! q
- }
' U2 [& v+ z+ |& A2 m1 h - else
! [% q) w, G7 {+ R! {; q - {
, C- G: E- Z6 r, }8 |. l& x - Task.Run(() =>
- K6 b( Z. A1 c! z( l/ U! ? - {
4 g% T% M' Y4 O# d4 R2 T6 U2 J - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
. E4 D) M* r5 W# t7 z - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
% Z% `' [' r$ v - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
' C. [2 K! `% e5 }) f6 U6 m - });, K: T; x+ x* I) T! \$ ]7 r* o" u
- }- U& e/ g1 h. d
- }. [' v7 s6 q4 }$ d2 L8 v
- catch (Exception exs)
& `( M, u' G1 O: P& H3 } - {. W: Y" Q- y. ]; q% n8 B2 \8 l5 \
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息' `+ X \$ H7 n1 E( S# x Q8 U& r
- }0 [# G B! T9 Q
- #endregion e+ a& V/ q; l8 X1 s) z2 ^
- }+ x$ F4 f4 u9 |" E/ w) N0 \( o
- else
8 P4 @# m- ]8 n) Q( q - {
7 Z& s! _0 B; Y - break;1 L* V+ k" v! G/ t
- }
# J& `. h% g/ z2 ^, v" l - }//while end
$ [1 F- I; i" I/ \( v - }) c( z& j4 ?: o
- catch (Exception ex)7 K( Z8 q9 d2 Q, h
- {
6 R! U+ w1 o3 D7 ? - //整体异常处理- l/ E9 m( \1 J, O
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
: j( f$ e5 i. ?$ J1 A - }
9 M- R1 v( ^ {6 R) N1 T - }6 T! U! b; o5 i& z' M
- ! \6 q& B" B' G( I, r1 U9 p; Y3 Y
& O! b5 E6 Q* I* v! v& w8 D- public bool IsReusable
; H, }) c: b; y# q+ i - {
! }( m7 `1 g& `; U+ A9 V" r - get
. b6 D* _5 g6 I# ^0 Z4 ~ - {
! p9 W2 R9 J6 }: h1 m2 Y, m - return false;3 t3 z% V" z% g, K3 a$ z
- }- e0 a! p: ~+ j/ A4 D/ N7 f
- }1 w+ T! s$ l$ {5 Q4 |/ |
- }
4 v& V: J5 v, n - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 / j6 I8 C7 e% W5 d$ K' \: a
|