|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 * x0 o" M0 B5 p4 Y- r3 J3 r" K* X
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;) H" i' d; `# y( E% `
- using System.Collections.Generic;8 G; C& y. f7 U5 H
- using System.Linq;
. C7 a3 n* _' \* i" I- ?: C - using System.Net.WebSockets;
7 Q5 q' e. h# S. Y4 u/ `( c6 Z - using System.Text;
& d0 c* L4 Z$ ?1 L( S - using System.Threading;
, V" k/ Q4 O, P, ]9 U - using System.Threading.Tasks;
' `9 Y g% P- {1 l1 A - using System.Web;
1 ^3 M# ^% Y- _6 B& u T - using System.Web.WebSockets;
N+ i, X, o+ C7 } - ( b- @1 A8 ?' T2 K( V e2 f6 t
+ z/ R U/ x: v% Z- {8 K- namespace WebApplicationWebsocketHandler9 N& h X U/ o7 |
- {
; S% R& p+ l' f* C7 P4 ` - /// <summary>
* T0 E0 n9 |" ]; N; Y - /// 离线消息( @7 A, ?, q; o1 J
- /// </summary>9 Z5 \- y/ J3 ~! q
- public class MessageInfo
& Z6 r6 ]& p% D1 v - {
+ ?& L) j0 D$ I2 S2 d" j+ ^ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
( M& k' d5 u6 K. Z8 q- c# l9 F) p( t k - {
8 g3 n5 L% H% l9 Q) }8 M# ^0 W - MsgTime = _MsgTime;
% K9 ~3 z' |$ x3 ]- Z - MsgContent = _MsgContent;% g% F+ I8 s6 I- ]
- }
8 e- Y5 U% \: G* H$ ^: y" O. T - public DateTime MsgTime { get; set; }5 r3 f0 b& X/ l' X# y
- public ArraySegment<byte> MsgContent { get; set; }
& H, t6 ^0 O0 N( j - } O. s. m! U# w9 D4 i, O8 m/ ~, f P& q
2 ` u$ i! @ J+ I$ M! s! n- 5 {0 w# j8 Q/ c1 m" H. T, e+ E' n
/ O" b" U a4 D, d& f
4 x1 ?4 a0 V/ u# j- /// <summary>
& ?9 P( X9 F$ r4 w - /// Handler1 的摘要说明% {7 W6 y2 F, g5 Q. o
- /// </summary>
p. F/ R2 r: z' ?+ ~ - public class Handler1 : IHttpHandler2 p: Y! s6 [' ^$ q8 x& [! v) ]
- {: v2 x: I& H, Z, W2 L7 P
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
5 p3 f5 }$ j& _: E - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
2 G$ q h, }! p3 x. R: P, v3 R - public void ProcessRequest(HttpContext context)2 u2 h6 L0 q, n, v1 }1 L4 A
- {
" k* J3 U) |2 t' |0 G - //context.Response.ContentType = "text/plain";. P$ i9 K1 G/ R4 k
- //context.Response.Write("Hello World");! [" e& }7 I# B2 h- e" L, @
- if (context.IsWebSocketRequest)4 D! D$ Q9 T! {+ T0 ?* U" m4 A: _& r
- {' A+ j" `6 }# `/ ]/ @4 t7 a" k6 y
- context.AcceptWebSocketRequest(ProcessChat);+ a5 b7 _& B3 o9 c+ y+ m2 d
- }
3 g3 j1 x( c+ X - }' Y3 ~+ o) o% r% n9 k
* ^6 z2 y# l8 Y& i- private async Task ProcessChat(AspNetWebSocketContext context)
# Y, p; m* V! O6 R: @- v - {, Y1 i; B0 l. m/ |2 W7 [. i
- WebSocket socket = context.WebSocket;
1 G0 x! a1 q: S; r - string user = context.QueryString["user"].ToString(); x- N) I+ R' m( ]& y- K$ x
- G' q3 P0 X3 j$ n" T- try
4 u# U( H S& Z$ h, I B - {
1 J6 R: [" s* b1 F0 h - #region 用户添加连接池
( ^* B' y) K; j+ q- Y - //第一次open时,添加到连接池中& _2 Z# [" @0 j& Q- l2 M0 E) U
- if (!CONNECT_POOL.ContainsKey(user))( L4 V. l1 @" o% j3 a. z
- CONNECT_POOL.Add(user, socket);//不存在,添加
. z: L! f" C' c( o) T1 I' \+ A0 u - else( Z( T/ B G S9 |
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新8 z+ q5 k3 G3 C) F4 I2 s
- CONNECT_POOL[user] = socket; _1 Y1 |% S6 q8 l: I7 v$ }7 ]
- #endregion
# v) F5 ?+ s; O, K
( m4 Q- w; U5 R2 g- L- #region 离线消息处理
0 m+ W2 T; W9 z) `: P6 t3 ? - if (MESSAGE_POOL.ContainsKey(user)); K. T6 ] v. }
- {
6 ?8 s- U. N1 W# x - List<MessageInfo> msgs = MESSAGE_POOL[user];
7 L) B' u) A( `0 Z - foreach (MessageInfo item in msgs)
& w8 p. }' S9 o( |; R - {* H" Z4 x; H6 s
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);! E' r2 @: g" X! c
- }
6 z5 A# }& F0 @2 ^ - MESSAGE_POOL.Remove(user);//移除离线消息
1 @) }' T- O4 w. i% \ - }% v5 C `; P7 Q0 }1 @% R
- #endregion
6 j7 I' Q0 D/ p1 x3 q1 E3 j - * h( E3 e1 t) E- f( D, |, s
- string descUser = string.Empty;//目的用户. _8 M" f9 U. K: |% e
- while (true)
) b5 r7 j- u3 r$ H( | - { q# y3 L! L! ]* f* h
- if (socket.State == WebSocketState.Open)
0 B( f- A9 C- B# ] - {
1 T0 o+ K! x0 @9 a P( d" h - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
, P1 l/ f2 v9 l# c: o6 F$ T: P- P3 o - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
8 ^2 o4 a8 L) k
: A: f I5 S+ V- #region 消息处理(字符截取、消息转发)1 m3 }$ `- ~% o4 s& \: K3 L
- try
; J# C( E; H" O7 L - {, |" X T W2 e7 t! Z2 h
- #region 关闭Socket处理,删除连接池2 R# X6 {9 l! Z9 D
- if (socket.State != WebSocketState.Open)//连接关闭, v! P: t- R0 ^. ?+ ]. S j
- {! a2 f6 t- c. B
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池- a& L: s+ Z8 w1 c; x6 }5 i
- break;9 [3 P0 g4 B- U; {
- }
% Y% {* m2 L0 g% T; C2 } T9 c - #endregion, C: R& {7 G: K, U
: X: }1 g4 M' b7 Z$ W- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
1 U2 i$ j1 p( R8 r6 g9 ]# C' C - string[] msgList = userMsg.Split('|');; n% f7 N$ g6 H9 g0 @# a& r4 J
- if (msgList.Length == 2)
9 W0 r" L0 X( f; c' A- M - {
2 g9 d5 \+ C- ~7 ]0 B5 y D! G9 } - if (msgList[0].Trim().Length > 0)/ P$ w Y4 l8 A
- descUser = msgList[0].Trim();//记录消息目的用户9 w8 b0 d, P$ ~
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
) i2 |, S3 n1 B4 c9 ~- `' u2 s - }( l$ l- B+ A" {+ H
- else
, M( `& N4 |; ^. t) u3 D9 K - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
7 y4 a, P* r( E7 p - * B8 S' F0 {- r. I$ S' i
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线1 ^) V8 j9 E7 H
- {( Z. u% H1 h; ?# u# k& u1 f2 _5 S
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
5 n8 G4 Q) v# {( } B - if (destSocket != null && destSocket.State == WebSocketState.Open). V) B' i: J/ x3 S ~
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
7 `% R2 S2 r. ?( L" I( N+ I - }
' O8 g4 \" @; ~0 M$ g% C5 J, | - else
3 l" @% ]: |- {- M+ a; H - {
2 m, T: f9 \; C) x0 n1 ^+ z - Task.Run(() =>
2 v- Z& d9 W6 N' e1 {8 [% W - {1 t' `! B6 x6 j+ r8 C6 ?
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中% r" d7 J% l1 o: N% n; S" U. I
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
6 g ~. v4 v# _! N a5 C: L - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息* m/ x; H5 ^, |. n, V& E
- });# o8 c: s1 I( }8 x* D
- }
7 o6 J' u$ O8 J/ ?1 T+ G% V" A - }
4 I h/ b6 {; U" S - catch (Exception exs)- G8 Y% s" H" |
- {
+ S) q+ D. L! ^1 q2 `$ B. c - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
: C8 E6 i9 g0 M5 W4 w - }, q p6 k0 j2 p6 y6 v
- #endregion
2 y+ X3 u Z( l - }# N( V/ I* l/ r( _1 J
- else
+ S; I5 [- j& v1 v$ I" Y0 D$ T - {
7 U* n7 I% x0 F1 r. ?0 H1 M. ~( \ - break;( R# ~: ~, k4 E3 |- D& `1 ^/ g' Z
- }" H2 V3 T9 E( I5 C% i( O, Y+ A
- }//while end3 [" k* q z/ s+ K1 a
- }1 o% P6 E! F6 R
- catch (Exception ex)
. [ p* Y' g5 \0 |2 x v! c - {, g0 m8 a9 t$ Y' f- g7 N
- //整体异常处理2 I5 S+ @# Q! F5 w, o2 T) Z/ W
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);( l1 r, R: q0 R% E# o, z3 H9 d7 @
- }4 h% P! V$ E7 i5 y( j+ E( L
- }
3 K6 Y- g( Z" x+ K: I - % M8 N" G7 P. T. ]" @" e
! k; W7 l. u( c. _; ?- public bool IsReusable
0 N/ r! I- }8 b - {$ d$ l0 R" P. y$ u0 f) ` E7 `& k) N* T
- get
7 F2 @/ d( ]" l s0 { - {' b3 d4 D0 F" O; I* N
- return false;
9 G/ X3 S( F6 I! d/ N - }' C+ R: Q1 p6 u- H8 J- G: y
- }
6 R1 m9 O8 v: Q i" z% F3 g - }
, N o7 W. Q, K9 N# p - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 2 z" U2 f, q" _: K# H; R
|