|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 8 k/ E C u1 @; F0 n: K/ ^
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;0 K/ D' b i) E7 M
- using System.Collections.Generic;
9 q* B" T' m1 ]7 P5 M1 W( K - using System.Linq;
; {6 k5 h) s" w' V- u D - using System.Net.WebSockets;. x7 ^/ `9 B J8 }6 p
- using System.Text;/ H9 m9 ~% h! {3 |( A9 L
- using System.Threading;
3 @' t0 c/ S( _7 A6 f5 E1 T6 C; \ - using System.Threading.Tasks;
' M7 M; g1 i$ y" y6 e - using System.Web;
/ W8 H8 o1 C2 g5 t6 S - using System.Web.WebSockets;1 f3 M0 W) K! ]9 {, n ^# Q
- 8 s) T* \) ]7 W9 f2 ~: J5 J- O# ~
* `1 C- i) L3 c- namespace WebApplicationWebsocketHandler% X, K- d- Y6 O* C; P
- {
; t/ a4 L9 g' y# i - /// <summary>) x2 x4 V9 a, N3 M9 H, o' m
- /// 离线消息
- L! G' @4 D* r# L - /// </summary>
$ ~3 ^3 r. X. F# g8 \+ z - public class MessageInfo
. i7 x2 a* ~. o4 k* a1 w6 O. Z5 t - {
6 {/ ]! |0 g" N* N2 X6 g/ Y# ~1 C - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
8 W1 e( {, R& t3 U - {
! k! l; K( `" H - MsgTime = _MsgTime;
& s3 q0 G4 B: L% a( k - MsgContent = _MsgContent;
. O4 J3 m M! D$ N5 [% Q - }$ @$ @+ d% F+ T' x& m" H$ O
- public DateTime MsgTime { get; set; }7 _' m8 E$ W* V' E
- public ArraySegment<byte> MsgContent { get; set; }
# t6 m! \$ l7 W: S. T4 ?$ p$ ^ - }
$ m1 c9 T! ?/ g/ R
% Y1 p4 s4 _; D- k+ f; b
; Y4 W/ w! a+ r5 R
2 b! A5 b5 m& r# l$ H: |- 7 E( ^; m! j. k* V
- /// <summary># @9 m8 r' Z2 C- y3 Q; p; [1 Q
- /// Handler1 的摘要说明
8 j u$ [/ w/ v* y - /// </summary>
: z' J( M5 ~6 d - public class Handler1 : IHttpHandler
- J0 f7 U; J: ]3 `* C - {( o: n0 \, W! g8 d* G# M& F) V r
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
+ w2 |3 u/ E7 h- d - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池" n$ d: Q7 |+ `, V
- public void ProcessRequest(HttpContext context)$ q x1 C" I: ?% L. j
- {
, H3 u1 i4 T/ e! p0 ~ | - //context.Response.ContentType = "text/plain";
i9 ]& ]; ]& f( E& R5 U - //context.Response.Write("Hello World");
4 h$ l9 z9 ^( a6 Q7 r( n8 h - if (context.IsWebSocketRequest) y' A& `8 Y4 r6 {$ Q0 y f. d& W
- {: h# S% a* M) `0 K/ {/ b
- context.AcceptWebSocketRequest(ProcessChat);$ _, W6 P* ]! B5 W
- }
1 L+ Q3 P+ v6 O. ] - }5 R4 p* ]& }5 u1 Y( j
- 3 h) l1 E/ }" V* m! S
- private async Task ProcessChat(AspNetWebSocketContext context)& P& t( v" b4 g }+ X8 Y: V& w
- {
1 n, B E H( T3 E/ r; I+ Z - WebSocket socket = context.WebSocket;
4 i/ l% r, S4 |8 S; e - string user = context.QueryString["user"].ToString();
3 V8 T# r i; s! \2 @6 o$ V3 S - 5 b- n& S; C. V6 h
- try$ f% z% l. ]4 g
- {% w% p( J5 s, O; r
- #region 用户添加连接池. c" l1 x- C* b
- //第一次open时,添加到连接池中
1 p$ L. b, ?' h - if (!CONNECT_POOL.ContainsKey(user))$ |0 j5 g3 p$ l: b, O8 i3 K; A
- CONNECT_POOL.Add(user, socket);//不存在,添加9 i# I# l8 Q: v9 S2 Q
- else
6 h5 D6 I- z6 k7 g/ E - if (socket != CONNECT_POOL[user])//当前对象不一致,更新0 O$ T: I6 y% X) C- K
- CONNECT_POOL[user] = socket;
8 U& N) A0 L% [ - #endregion; g. n* ?, E9 ]4 V
- + @+ s. ]" {) T: E! [. O
- #region 离线消息处理 l) T" d" D/ \0 A
- if (MESSAGE_POOL.ContainsKey(user))4 t# A; x) t& C: N3 }+ B% j$ l( w
- {
3 g2 a3 [, j, E, L# H1 s: X8 Q5 x - List<MessageInfo> msgs = MESSAGE_POOL[user];
4 u. T. Z8 ?5 {0 x% S - foreach (MessageInfo item in msgs)/ F' l5 U0 P% B# C( y
- {$ H: Y# \! z: r% W8 k5 K
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
: C+ W i$ c3 `0 n F. \ - }
8 D4 {& F+ G& P* e, z: s - MESSAGE_POOL.Remove(user);//移除离线消息3 p9 v$ h7 e+ e. \2 d
- }! q; O0 }8 |. g1 }" T6 d( K/ j6 ~
- #endregion& E2 v* {9 y- u; m8 h6 X
- , _: m% J& @0 T$ m& P* ?! U" W9 H
- string descUser = string.Empty;//目的用户9 K4 P' T0 q2 W7 B" L" `
- while (true)
/ S& K4 z: h* g/ n7 q/ T6 P* P0 L5 v - {
! d ]) o( u( l8 O( H2 D - if (socket.State == WebSocketState.Open): J$ Z% S$ A. y: m
- {: W, F$ M( X; Y' ^/ Z/ A. F& J! l6 q
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);4 ~, _3 k! V! c9 T
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);& g+ z9 j# s& ?) |
- & G3 a7 E! j& V& g& |" h
- #region 消息处理(字符截取、消息转发)
% @, N9 i* x- o' M# f - try5 e- T- |2 p5 g& e: @
- {+ I/ G9 \! Y! T
- #region 关闭Socket处理,删除连接池
& [2 w1 ^' G/ @8 g - if (socket.State != WebSocketState.Open)//连接关闭0 `- j8 i7 J0 T
- {* ?0 M& }4 F2 _# ~
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
2 _9 U. _9 \) V% | Y - break;( Y& B. J( ?3 S
- }
- t$ A3 j2 y. E8 J3 |+ K* @ - #endregion
2 A9 j% q; K1 g, V- M. K# {7 j6 O$ N - + C6 f! g! J& h8 i R2 {
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息+ y0 ?+ x0 M& p. j3 \
- string[] msgList = userMsg.Split('|');& e8 K9 R$ \) Q# k6 a
- if (msgList.Length == 2)/ e! a# `9 k7 |5 d
- {4 ^! O6 O9 B. X
- if (msgList[0].Trim().Length > 0): s5 Q; {6 q6 |! ?& h
- descUser = msgList[0].Trim();//记录消息目的用户
% Z& v* j! x! ~* w" {% `7 D( o - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
4 q9 P3 R* W1 v7 h - } m" k0 {+ J7 k4 R
- else2 i2 y6 n9 g; a w& V
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
2 g0 v5 B; a6 R7 L; w5 o) ~
% m, s# j5 Y% n# C9 M- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
0 J# J3 S0 g7 \8 q- O; v) M B. ? - {
! I5 f+ I- R4 D, ~- ~5 r5 ] - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端. ~6 N! |: G6 e5 }/ ?. n. O
- if (destSocket != null && destSocket.State == WebSocketState.Open)+ V: z/ z, e4 r- D# k$ k9 Z
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
3 |. c# [! [$ e8 s - }2 \( ?5 g# Z5 v" f: u/ p0 U
- else
. k0 s! i- g) I# v - {
7 Z/ m) e# h& o; `8 G - Task.Run(() =>
: G( G U* q0 k5 F [! O& T - {
! @* ]' D( ^! {$ I5 C a. p S - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
2 G0 w; s0 \4 Z( r1 I5 u) c: \! n( O - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());$ E$ }# N3 H3 g) ^6 k8 c1 ^" H- h
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息# r) F0 w( X4 _: @) h) x
- });
/ {$ G8 I1 H, l! U& N. E9 B - }9 M1 w/ a7 s8 E& ~: d
- }, q( d% F; ~! s0 |* \$ h# r m
- catch (Exception exs)
( h0 s( L6 \% b0 W! }. a% y) c - {: r& V7 Y/ ?8 ~. X( F7 S
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
5 `/ u+ T0 m/ }: ?, y - }+ l+ U9 K; B# d5 _" E
- #endregion
+ {8 N3 b4 v9 }( o- Z* H. Z' h+ ^+ c - }! g2 Y, N& Q F$ `) \
- else
. T6 I. \4 l2 C& y2 [* Z+ S" Q6 }5 [ - {
8 ?3 h' B% L' {( N0 I6 z/ a - break;
7 I' }" E! e+ M, q5 g. w! t - }
7 J% R* x6 B! R - }//while end
0 r t& V2 J- [% y3 ]' P- `7 Y - }. B( k6 ~5 K& {) x( O
- catch (Exception ex)
7 f) n/ S9 m* `( y' j. n - {& S( g4 S6 `+ d8 k) @4 y+ T$ e
- //整体异常处理
+ j3 d, {7 q" o) l% B - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);$ O' s+ x7 C# E% h4 K r' n
- }; R; G1 y! o+ Y9 N! G- x
- }( Z+ y" |$ N; P+ _
; C8 F7 i% R# \/ e4 U& O- ' ~+ ?, ~8 g9 Z" u$ l1 b
- public bool IsReusable
- [+ q/ R) r" f+ S4 x - {
- c a- B; T F# `% G6 O& I - get
+ }! s1 }' U: z5 [3 d) D3 e - {
8 S0 p' n' `6 K& w - return false;
6 v! P4 P! }9 r4 C4 Y# z' x8 A - }3 M G( W: F' d% ^! H, {+ n
- }
) I8 [) Z, |* b" J4 T% m5 b* ^ - }0 Y5 p; [) k& P, q! S) c! F
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
! w- g! N! F* V$ Y& q' p |