|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 . G( N `0 [, e5 Z& f
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
& N: r5 g% ~1 v) x- e - using System.Collections.Generic;+ O" r, j" a: T/ g4 [
- using System.Linq;; H% p& k7 }- p0 X9 W
- using System.Net.WebSockets;) `' Q/ V$ \! R" R7 ]0 ?9 N! A
- using System.Text;. n# V- u3 @5 m. ^8 Q: b
- using System.Threading;& q' h$ I# F/ \& n, J- E( D0 @# c
- using System.Threading.Tasks;
3 H( L* m3 m8 G Y; ]4 R - using System.Web;. l8 L3 V R4 W! i9 F1 x: Z5 g
- using System.Web.WebSockets;
4 x. {9 e6 d0 i$ Z& K8 t - . N, a9 V8 O! D" W! H
- 0 Z/ S: g9 ^9 [
- namespace WebApplicationWebsocketHandler( f/ n% @3 }9 Y/ g+ U9 a
- {
! _* z( D8 Y; i1 x - /// <summary>3 y! ]" x0 _7 q ~' D9 P* z
- /// 离线消息
" b: r& T* }* ] G1 M z! i' \ - /// </summary>; t4 [3 ]0 A7 G2 ~: Z! _$ |% W/ ^
- public class MessageInfo2 a& J' a, x7 b) u4 B) N7 _! d
- {; y# R) ~! T9 F' z# D
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
6 y/ I) f2 i1 G; H5 y/ k$ ` - {0 s/ z4 A) C" v! X
- MsgTime = _MsgTime;/ v' V, _3 c+ ?& F% a& ~4 X0 p
- MsgContent = _MsgContent;
2 t( B" C# e! c - }
m/ d, S; E6 [) {5 w5 k - public DateTime MsgTime { get; set; }
; c0 X# G8 ]1 t1 ?3 i9 ] - public ArraySegment<byte> MsgContent { get; set; }6 r1 w; t( j- }, J# K0 e
- }
3 Y T$ F- }) M
) F6 E, O0 F$ [/ F: a8 D- h' J8 P" |. U2 E- y- M( _
- 4 b% ^/ a1 F: P; d6 `
- / A* G* r; s0 _9 ~: ~7 l
- /// <summary>
, D' {6 A$ }5 T7 a$ l1 M - /// Handler1 的摘要说明
) ?( q' f1 M3 b5 [2 j U - /// </summary>
' A/ }; Z, P7 K - public class Handler1 : IHttpHandler% a% q6 V, h) d0 S6 ~' z, J
- {
5 m1 U) x$ G2 H8 ^3 ?+ @! m8 M - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
% y- ?) B0 x9 L, i3 t8 T - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池1 D. ? A) T c
- public void ProcessRequest(HttpContext context)% {$ j2 _+ r8 E. |4 Q) i
- {$ f" Y8 ]) U* `1 U) O8 i' ?3 P
- //context.Response.ContentType = "text/plain";$ ]8 W, k; r, C7 D
- //context.Response.Write("Hello World");9 l2 v$ M- j: D
- if (context.IsWebSocketRequest)9 v0 w B" E& S
- {5 K: D& `7 l- o: g) S1 n& v" [
- context.AcceptWebSocketRequest(ProcessChat);: {4 d( [6 _, e
- } ' z. I# T' e* b
- }" Y# i+ {' O8 H$ i" ~" w0 S
2 J% _, g* V, T- i$ A- private async Task ProcessChat(AspNetWebSocketContext context)
0 v+ K, x: s: o O - {6 K+ } j. U+ J" b1 W8 }
- WebSocket socket = context.WebSocket;
1 Q9 ]6 g. z1 m' m - string user = context.QueryString["user"].ToString();
7 N, `; Y! R7 c6 z - : e) q) V4 B; Z3 V) R y6 p( ?
- try6 s8 }8 D ]( j' v* L5 c+ s: H
- {) Y& M9 G' Z# n# o3 P, w3 B- ?: N
- #region 用户添加连接池
& P- Z6 y5 d8 X3 ^" v& [ - //第一次open时,添加到连接池中
; `0 w' r0 ^2 B8 ]! G - if (!CONNECT_POOL.ContainsKey(user)) a0 ^) ^- J' y# O" }6 y, i
- CONNECT_POOL.Add(user, socket);//不存在,添加
) K/ @; G0 z3 K& C1 n" l! n% ^ - else. I w: Q9 r' V7 A$ w. D
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
8 [# j0 h9 ^- c9 x - CONNECT_POOL[user] = socket;, v9 }$ \% a5 E9 {* D( s
- #endregion
+ @- ~: K# W# Z( @6 ~2 s
% }: y8 E8 V" O/ ?7 @- #region 离线消息处理
$ v0 Z( t o6 N1 ^ - if (MESSAGE_POOL.ContainsKey(user))% T6 R4 U; I; I4 l
- {; U2 {$ ]# E" W8 H) s6 D6 a0 W
- List<MessageInfo> msgs = MESSAGE_POOL[user];
- f+ w/ @. R* ]2 D1 x - foreach (MessageInfo item in msgs)6 b2 s' a1 P( U+ b
- {
7 R8 }$ \* {- Y6 D! \) v% R - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
9 F" t* R& U# h& w( ?, Y - }
' v& X, L) P" ~& | - MESSAGE_POOL.Remove(user);//移除离线消息
9 k) S; ?" C# J - }, G' S8 F- R+ }. K2 q
- #endregion
: c+ i* {1 `) ?9 Y) h - / }9 l- p8 `! ?' d) e
- string descUser = string.Empty;//目的用户3 U+ a& O, P+ M% Z5 ]! o' A8 b
- while (true)
, X5 S: q4 _, W8 P& f - {) Z. D" E1 P/ W0 ^' d, }; X$ X6 U
- if (socket.State == WebSocketState.Open)6 y8 ^0 A$ e6 r/ M' _
- {, Z) j! G& n5 v" C7 T2 U/ H. z) d
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);0 q' }" I; k5 ^' m1 o2 z7 U0 j6 v' U
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
4 G3 ~& t, Y# X9 ^6 S - 8 h7 l4 f c' Y ?2 P' Q) A
- #region 消息处理(字符截取、消息转发)
7 \0 L+ h! m$ Z9 z" o+ H2 O - try
{3 |! [( N1 m7 ? - {' Q5 J4 O( R! o; t2 |4 I4 ]
- #region 关闭Socket处理,删除连接池
% Z6 J4 |/ u5 ~8 o/ x }% I - if (socket.State != WebSocketState.Open)//连接关闭# F# L1 k4 s( r8 L0 D4 Y
- {+ h, Z9 u6 I& P: K! [* @# }
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
( u( w* Z; g" v) x - break;
4 ~# Y- D! Q# `; g" F* B5 \, { - }
% I7 ] E0 K6 |2 Y* x - #endregion9 @- V0 s3 W+ Q2 L" b! t
6 v3 U1 W1 g- K9 j2 {8 o0 u- O- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
0 w. B" K0 j- ]; P+ W1 L( T - string[] msgList = userMsg.Split('|');
g" Q+ u- T2 `! @/ I# l/ | - if (msgList.Length == 2)6 H, v9 \' T6 {3 Z
- {
7 z a5 D# s) Z& F8 W# p& z6 m - if (msgList[0].Trim().Length > 0)- B1 c- g, x) Z1 T% E
- descUser = msgList[0].Trim();//记录消息目的用户
. X- y' m9 s% m! U& L( f2 n" D - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
9 b; G6 c' U, p5 Q7 U - }
. v5 a" n% I: v; T1 @& `" r - else9 m' `7 ]6 y& @6 D/ [2 ]9 ~
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));3 Y, w) G) c9 M. P# `! n6 s
- 2 z) P- P: ?5 K( V: x
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线 a" e% X8 T1 ]% Q
- {! r! U7 J" j: B
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端4 F+ d; e( [& s6 `2 V" E
- if (destSocket != null && destSocket.State == WebSocketState.Open)
* }# }$ a# m8 |5 B+ {2 q- t - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
0 q6 P4 {! |; f4 n* c - }
+ D3 F0 N* B. d$ X: _$ F/ o - else
' }# `- e( h4 X9 z) F5 S - {
, H7 ~" T2 ~5 c% P% P9 t - Task.Run(() =>0 m5 S9 x6 q& u$ {+ `
- {
+ S, P" d7 B$ n1 ?, a2 ~# E - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
( a& \( [/ w! ]7 b2 h9 u7 J' M - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
$ y' y5 y6 V8 f5 O - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
+ W9 W4 w' L3 F2 b. I - });2 R8 l- q8 o; U3 G; A9 J. M
- }
9 W9 T- m5 e0 j' F# C1 _1 ?; o - }
$ Q5 u3 f6 |' ?; _# x - catch (Exception exs) F8 l1 a; z2 W# h( f
- {6 M/ d: i' X" X# [ o4 Z; |
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息6 |- m ?5 P* o1 D$ \& l/ ]
- }9 F+ m6 ]5 M, c
- #endregion
8 ?* p' h6 c: _: F" s9 S# p# _ - }
* r, j& {, N) `* _* N - else
" _" f. i9 N4 t( g - {5 E: u. D6 p; p8 N$ \; L' S
- break;: V) u @) p- ` B8 S/ v3 Y" z
- }
7 J$ Q E- D2 l - }//while end- g8 n/ J* s! s8 c7 {6 R ~: |. S
- }: c& m7 p; n/ X; \% a* Q3 \
- catch (Exception ex)
: X/ t( y% }2 v- N5 K# b F - {( g% \7 j8 p2 u+ h* W4 b8 p
- //整体异常处理9 k* T5 |6 Y, x' P3 W [. O
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);( |% H! L1 D$ X+ J4 I o6 E' |
- }/ z1 O- Q9 z+ V) b
- }
5 t4 B: o( {* n6 ?; i
8 p* A8 ^9 ~4 {0 S+ j
' ]6 E d+ U5 O* ^! p$ ]6 s- public bool IsReusable0 X4 L9 p; o2 n5 `( v& R) ]
- {7 [+ ^6 x3 B2 R1 ]1 @7 Q8 S, b
- get
0 t0 e/ a9 n" D( m - {$ E, ? r" T4 G( e$ w) f8 n
- return false;8 `! D1 Z2 A( m
- }
* J* i' a q4 _1 `* b - }
5 G5 j' `# u9 J( r. Z6 Q l6 a' O2 Y6 ` - }
$ K8 w5 F. Y) X. b3 I. f - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
. ^' G* C$ O3 P! E |