|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 6 R4 g L1 b, r" ?" ]7 F. }
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
3 ` K; I5 J* G, s$ R - using System.Collections.Generic;
* e3 H0 X* }- E- q6 D3 V% n. m - using System.Linq;0 y. x3 U6 H" W& Q
- using System.Net.WebSockets;9 D9 I2 v+ b0 c; F# e
- using System.Text;
9 d$ l1 e' b# W4 r% p7 v% y+ b) a - using System.Threading;6 j8 V- ~, U9 N5 o
- using System.Threading.Tasks;1 a* ?, [. ]% I
- using System.Web;
% n6 s0 V* |3 u' | - using System.Web.WebSockets;
. V0 {! ^7 G% o# |5 v2 G7 ?
& c" S8 [" ^. d( E( k3 _- 5 z! n$ {0 E! w! [/ X1 W
- namespace WebApplicationWebsocketHandler6 k9 S$ ~: E: [" }" _5 a8 F" ~/ m
- {
5 Q. f2 n7 h; I) t - /// <summary>
( O, t# C. T4 l6 _1 ?) p" K - /// 离线消息6 n7 h8 Z9 S" B; ?6 _8 j
- /// </summary>! S, j* y: g- c
- public class MessageInfo
& n8 W7 o5 e4 {4 u - {
7 J8 \' V3 U, Q( n5 ?2 i4 e2 J- E+ g - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
# q' v7 {. E9 R# s - {8 N' H7 i- L. i: E$ R
- MsgTime = _MsgTime;
& U0 w' H* D2 [$ U8 N! O - MsgContent = _MsgContent;
' B. L- T5 I9 i3 V# }" x, ?% ~4 A) b - }
8 F* { [( p [/ P& i) T - public DateTime MsgTime { get; set; }
l# y3 h, J# M2 r; a0 \) Y - public ArraySegment<byte> MsgContent { get; set; }
* {- q/ N! a, z# Y- u1 G* y - }
9 \+ ~' F/ I. l& O7 y4 [9 l5 t
9 |+ H, d& d% k; z8 d/ y$ e ~- 9 e5 S9 [3 b1 R: g. I
- 3 U h. S+ m" t0 L
- 5 R; E$ {& s4 C" [9 Y
- /// <summary>( {* ^, q0 T. u4 l) v q$ a
- /// Handler1 的摘要说明) s7 h! H Y E. D1 V/ M
- /// </summary>
! S U2 q1 q/ Y. n0 L1 { - public class Handler1 : IHttpHandler! }* M) c4 C; s
- {6 C8 `$ f$ c: H- U
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池( P6 a5 m# V7 F+ \
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
7 i, Q1 o% x0 r3 X - public void ProcessRequest(HttpContext context)
; h- ^! b; d5 j4 ? - {
p2 h( L- h- v - //context.Response.ContentType = "text/plain";
6 B l2 v1 s: f8 f - //context.Response.Write("Hello World");/ i/ X& K; a/ ~2 Y& V, }
- if (context.IsWebSocketRequest)
$ w: _ z: r4 ^- X) O - {
0 x6 y9 e* O4 E0 i9 t - context.AcceptWebSocketRequest(ProcessChat);1 c$ \9 |4 j( o& I
- }
& D1 J9 b3 o" R - }
( ]& ~0 N6 U2 \+ R' {' E
+ x9 F- p S* p+ G5 q$ ?- private async Task ProcessChat(AspNetWebSocketContext context)% a& P! M, ], ~6 y
- {. o2 \, E, F" Y0 Q# q8 T
- WebSocket socket = context.WebSocket;6 F2 R, ~ @. ]" k* R b
- string user = context.QueryString["user"].ToString();# D u' C/ \! m# r3 D9 @1 t
- ; q: a% |1 k# Y8 j" d, b
- try
7 ?; I$ p9 l0 A; n+ Z - {
% |5 K X8 I" ]) Z+ Z - #region 用户添加连接池
' v6 U: N7 K; A% T4 e - //第一次open时,添加到连接池中
% d4 T3 h5 R: l6 s - if (!CONNECT_POOL.ContainsKey(user))( L8 ^$ y) X- F' g) [
- CONNECT_POOL.Add(user, socket);//不存在,添加
* U1 Q/ n# |, p4 p/ o" C - else
" i- J2 k& \/ b @- m - if (socket != CONNECT_POOL[user])//当前对象不一致,更新! X% \3 i- e' S7 k
- CONNECT_POOL[user] = socket;8 E) n, i6 X7 ]9 a! N, l* n: T
- #endregion
: @9 M0 q, y& l, T# v
" |/ E+ P6 X9 D& H& F& R- #region 离线消息处理
) [1 d* s' r4 d% {2 u0 Y - if (MESSAGE_POOL.ContainsKey(user))/ Y, i& t& f. ~1 j) {
- {' h) v% p4 H; R
- List<MessageInfo> msgs = MESSAGE_POOL[user];5 P" {; N% G. o- R
- foreach (MessageInfo item in msgs)' n; L# K1 ^$ k3 C% F2 }) s
- {# M1 ^ I, M: @& T: C/ n
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
0 |+ V8 A) N0 I9 d: r0 Q' k - }
6 H9 M& o- j& O3 k - MESSAGE_POOL.Remove(user);//移除离线消息$ U: q- K" C! j9 ?* K
- }
2 ^* Z/ a5 J1 ]" C - #endregion
6 K" g" L) y! v; A+ J" m0 D
! b9 z7 @. d( C; b' t- string descUser = string.Empty;//目的用户0 G. `1 |0 [3 b7 J/ B. G
- while (true)
* v( m& B- p) O1 j - {
3 ~- M8 T, j8 ^( _0 }# [0 n - if (socket.State == WebSocketState.Open)' R8 N4 H" e9 {+ Y, D. b' g
- {8 N% N6 w, Q9 O. ~1 ?1 P
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);2 p, [( f4 s5 P( |6 @0 s/ \
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);: e3 L) V3 u' o8 o
! @% N5 U" p l( S2 z$ A- #region 消息处理(字符截取、消息转发)
! o1 T8 D. d; c' ~ - try& b! Z, G J: h8 h6 n
- {
/ D2 ~! \4 F) [( v% o% [ H - #region 关闭Socket处理,删除连接池& A; ^6 U+ S5 ^# k
- if (socket.State != WebSocketState.Open)//连接关闭
: y% [' r6 x& a- F, _ - {$ |; r' L, ]# W; V
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池1 O$ j: {* u9 l# E
- break;( S% Z, n' u G, }. N
- }( d% }5 R+ p3 E8 t* L
- #endregion- L+ M% v3 r3 b$ s5 N: B
0 I4 ~' c7 w% H$ l- _0 V* J8 f- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息 e( p' L" ^* n1 b I1 e! \2 m9 s
- string[] msgList = userMsg.Split('|');
0 i2 m4 u7 o' g, X - if (msgList.Length == 2)0 E) I1 ?8 p* L* ^/ l
- { ?2 x2 X, E7 g2 E X# ^
- if (msgList[0].Trim().Length > 0)
# y* M# U8 ?3 T* s f+ _2 H - descUser = msgList[0].Trim();//记录消息目的用户
, [' x( L/ p: `9 O - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));0 _- c' y1 a" {9 g+ ?, Q
- }+ n, O$ l& T# p9 R4 t1 b
- else* e& x- F& N E( R' H: q: |
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg)); @/ v$ `8 A: g( G! w" o
7 s1 c/ ^, {; x% G$ w- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线; ]- v o: ^% o& k/ l7 S E
- {
& |9 T3 t$ p+ q! [, ?0 W - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端: K9 P* J' f) Y* g" S
- if (destSocket != null && destSocket.State == WebSocketState.Open)
# s+ V3 ^- U2 }, H2 o: t4 I - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
! {4 B. p! I/ E - }# R- V3 o! Y' P3 O8 g, V7 j
- else
- ]; _& \% p e+ Z/ k# s - {, e! N9 d# p E
- Task.Run(() =>
5 G4 p" w/ l T; |1 W9 I2 d - {
$ Z, U* `7 X9 I4 G' \3 y- x% T - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中& @4 h$ g }2 i2 `, a
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
3 o+ q x3 m4 g; h2 E+ K# h - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
! F4 b' H. _5 K, `$ N' |' p - });
7 \- q8 }' o# y& O2 s5 G* I - }, R( T0 n4 I T$ l* s, B6 c
- }
5 s! x1 K4 M/ l1 V; i - catch (Exception exs)
& X' W! ]9 |& f; q - {
! M3 _# K3 ? Q& R0 t0 \- { - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
- l$ U2 B6 k3 c! y - }$ Q; ~+ @7 y5 W) Y" f4 ^' K8 K
- #endregion
- M' n) m) i% B5 ~+ d) e - }6 h0 q0 M0 v1 v& p; ^- Y
- else/ \# a y0 ]/ q
- {
# ~" _4 z+ s* K - break;: @ i0 X7 e/ |& k5 K2 p) q' ?( N
- }: [ o7 l; `) U& \5 D
- }//while end$ ^8 f) U4 b6 E, [4 e( V4 S
- }
7 h3 Z$ _6 D8 U2 ] - catch (Exception ex)
4 A& `8 ^0 [, i, S; f6 M. ` - {
( \$ }+ D q" X' U/ E; k/ S! d4 } - //整体异常处理
' k+ d4 Q& ?& R+ Y0 [ - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
3 _; _* G+ r$ J4 n: S) F - }! L' x. v: i1 q6 w3 j
- }9 F1 v1 e( q: ^
2 Z: V2 B1 f/ N% A3 P- N8 f- $ P" _. A6 d3 Y0 w
- public bool IsReusable
5 p- r9 \1 l: O) I2 R - {
' Y: M$ [( `; R; t9 U& X! l - get
, V% }; L; t" y R1 ~2 P) O2 { - {/ U! {+ K7 r$ H4 t2 x: e$ D
- return false;
7 }8 I6 Z3 `; E6 Z7 F! k* X - }
5 l0 c4 @% Z. A$ ]5 T/ d) V2 V - }: S* G& [4 P3 O
- }
5 z; m: Y5 c* r5 Z' v! h8 X - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 9 S! _; M/ b! t% |9 Y6 F
|