|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
4 T( g d3 `4 s& p. o" a8 P* ]2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;& [& l1 E' @1 y& _
- using System.Collections.Generic;6 I& x' u, f$ K# B) W
- using System.Linq;: l- T/ L8 b8 a( V8 W
- using System.Net.WebSockets;( v% Y6 B ^ g! V7 L A! f" l2 n
- using System.Text;
: D( M- s* A1 D) h6 t3 }; v7 W - using System.Threading;" D% K5 u% U9 R
- using System.Threading.Tasks;
: F) [+ \0 e# R - using System.Web;
& l1 D1 F2 M( E4 F# f( B4 H - using System.Web.WebSockets;8 e: K1 Z( S* N5 M8 p0 i8 ?; T
- 3 ^; {- M* |; x% f5 |
) i8 V& U: a& {- V) x" b6 b0 o+ a- namespace WebApplicationWebsocketHandler' e0 }" _* [: N
- {1 ]0 a4 ?* s1 i A
- /// <summary>1 ^' F( b7 p" X6 L3 T; k
- /// 离线消息
2 Q5 q6 l! ^5 ]' u$ \/ V. D4 y Y - /// </summary>% w t0 n6 {9 V8 E6 {: L
- public class MessageInfo, \5 N. H, }$ H& `8 f" q) ~
- {9 R u5 X( K9 q7 L
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)( m1 a* V" ?8 z2 |% [$ K
- {
0 {# N/ d1 y$ c% C' I6 O: H - MsgTime = _MsgTime;
: r7 E1 ~* L! t- S - MsgContent = _MsgContent;5 t- I+ z4 t- b% t1 ]* b9 m
- }' `7 y% }4 l$ s: u
- public DateTime MsgTime { get; set; }
& Y! R7 b3 ?( H. p" [ b9 q - public ArraySegment<byte> MsgContent { get; set; }; J p/ }; L/ h: N5 z! s* U- x2 \
- }' D9 W4 q& p$ v5 o
- 1 K* @! L( Q7 C( i2 _$ H
+ a8 g7 G3 r2 i: S% O$ H- ' s- d W+ _' \2 ^
N: j1 K0 o# B- /// <summary>
: Z) e! v- u8 Z3 v - /// Handler1 的摘要说明
2 U/ y' a" z" X! s+ e+ M8 p' I - /// </summary>1 f- N# I+ i/ \" D7 ]5 f
- public class Handler1 : IHttpHandler
6 l; L6 K" \ E+ Y3 q5 v - {/ K$ [7 S5 g$ q3 E7 p6 g+ u. X
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
/ K" W: S- d. y% d" i" o1 ]) h - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池. v7 U. ?8 u4 p
- public void ProcessRequest(HttpContext context)
$ f3 N% W4 x/ M1 \/ S) K! s - {
/ n1 h' h* j5 A - //context.Response.ContentType = "text/plain";
6 ~ w$ {2 E o" f) I - //context.Response.Write("Hello World");; I5 s/ q, t6 Z+ {: @
- if (context.IsWebSocketRequest)- f# _+ j/ ^. x: e2 o
- { k( H9 t# q( M) X- J! i
- context.AcceptWebSocketRequest(ProcessChat);6 x' C- O! N- |& j1 X' V- n1 q* B6 {
- }
. L0 z& i( h3 |8 \ - }
. h0 D5 C* ?# g" V
9 f; h! D; u k7 e+ _! K. [- P- private async Task ProcessChat(AspNetWebSocketContext context)3 J8 l3 t3 P, B8 e3 r
- {
* t3 t* H) F% F l - WebSocket socket = context.WebSocket;
; q8 [, J- O7 A8 \5 b - string user = context.QueryString["user"].ToString();: S" S: U, N) g# `2 ^/ z) b
- % C6 m8 C H- }: y- s
- try$ n( u: B: O, O1 k+ v& i$ T
- {4 L+ e) ]& V W
- #region 用户添加连接池1 \( i9 U6 U6 T6 H& P0 t: U/ q# J
- //第一次open时,添加到连接池中6 a: `2 R7 W* R/ G6 h+ p6 `
- if (!CONNECT_POOL.ContainsKey(user))
@- m* Y6 E1 a/ x7 Z - CONNECT_POOL.Add(user, socket);//不存在,添加1 y$ A' {; ^$ l( \
- else
) G$ S1 u4 Z4 d% k$ v7 N' a - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
+ {5 V% ?% `( V! i - CONNECT_POOL[user] = socket;
# r* T9 C( C1 R% X# n% f - #endregion2 l. G+ q( H, k9 C3 Q7 m5 D9 P
- - @7 `/ |: e( K$ m+ _" T
- #region 离线消息处理. g6 ]+ l2 J, G1 R% L
- if (MESSAGE_POOL.ContainsKey(user))7 p9 v! t# U0 L8 K" }- x; B
- {
5 t# w6 a1 H5 i7 v; ~: g - List<MessageInfo> msgs = MESSAGE_POOL[user];
j! ? F: w; W. _ - foreach (MessageInfo item in msgs)
! m; P4 D+ w- ~, l - {0 ]* u) v- e5 v4 R) \
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
( N% [, P; y1 m - }
' l; X- S/ A6 L: s4 ?, [! q+ {) V - MESSAGE_POOL.Remove(user);//移除离线消息- _" o# Z$ @: q) w: n
- }9 P$ c0 A: w* x( X; n! Q* w# e
- #endregion, q$ O# k- F; ^4 X( E R; b0 {
1 m( p2 \7 \0 F4 K7 K- string descUser = string.Empty;//目的用户, d/ b# U3 O5 q0 J) P: J
- while (true)
, Z3 V6 [' @! i$ z, c - {
6 Z, L6 z* }# r - if (socket.State == WebSocketState.Open)3 b9 u2 D2 c; o+ o
- {, j$ c0 J4 {4 v8 l( I) C2 W
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
, l! g: s: {* H; `8 P - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
0 y6 b7 Z* O4 K8 R# U& P$ M4 X - ; b+ Q4 }2 w0 K* i
- #region 消息处理(字符截取、消息转发)
; d+ m1 b8 O( D; \! T7 ` - try7 a1 N9 Q8 H9 I) n! n7 w- C; K
- {: t5 @9 J9 H: R- Z$ [# p
- #region 关闭Socket处理,删除连接池
5 H/ t5 U$ {4 u+ p8 b- Z - if (socket.State != WebSocketState.Open)//连接关闭 }- |6 \ s: ^9 U5 k; ? c
- {
7 O$ A& K; @ S/ Z3 L g - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
3 [6 y3 J) J% P3 O - break;
8 x% j- M% b9 j U - }
* \- F W" q" ]2 ?: s) Q - #endregion
( A/ n0 {* |1 q4 y
' N/ O7 M# i5 _& L6 J- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息( I) Z( w* y: n& d( \' q: c
- string[] msgList = userMsg.Split('|');7 P, z7 s8 Q+ S4 M* M
- if (msgList.Length == 2)
& B; \; w, H! p, B. j# G - {
9 q! N6 O. l2 I* d - if (msgList[0].Trim().Length > 0)' l9 H$ o. l; A9 g0 V( L
- descUser = msgList[0].Trim();//记录消息目的用户% m0 Q( `0 G) I: z( \! M
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));# K5 ?0 E8 X# g+ S; a6 w- |
- }% U- b! y+ I# n' R6 I4 y
- else3 v T8 T0 a+ H. t7 ^
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
! M( s, H: U1 W; c/ \ - 4 w8 | N3 }/ R' i% v+ C1 z, h
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线7 f; g+ A8 T5 ^5 x
- {
; Y T2 l' Y% y% \/ i0 N - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
' ?0 u9 U8 ~- M0 r7 s* r8 H- _ - if (destSocket != null && destSocket.State == WebSocketState.Open)- {3 }' p$ X6 f
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
" P& y* a) M3 }( M - }
- G2 K& V6 Q8 c- _/ p - else( G a- m( L) C
- {
& y; {- @3 v* W O - Task.Run(() =>5 u$ E8 `9 P0 X- C
- {0 a8 a. L4 t0 p4 U5 M$ j, r( a
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
( L1 G/ i" U( } - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());9 D+ | Q" U% |6 R% I" {
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
7 P3 A2 {, c" Q6 t( p+ Y+ L; R x - });
% x t, w5 ^! b I! @% t - }8 p, `$ g4 k4 ~
- }
5 m/ e+ u: A9 x! G F3 I - catch (Exception exs)8 a# O Y' O6 J6 F4 r
- {1 D( Y6 `4 H" u& G! _
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
A m; J: ^3 ~7 A3 ? - }
. q! ?. P, p1 f n3 V" h - #endregion8 d# W& r* X" t: z
- }- [2 K! u0 T9 ?& h F' x' L' {
- else: [) n' f) R& |' _
- {7 l4 q1 @0 e. E z A/ T
- break;& ]- y8 Z% o2 d/ K4 [8 G1 r
- }
0 _; W' c* H1 ~( e+ G - }//while end7 b {7 @0 H3 e* L0 g* U n, \
- } G3 Z5 n' P9 R
- catch (Exception ex): j, L' X) r1 h& [
- {2 f w6 ~: s$ C. J/ h+ {
- //整体异常处理
) q/ y1 E7 Q, b2 n% X - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
# }3 k) N; j6 u. A - }
. \, s/ K" g S% P9 T - }
. C i% m: N# j" z+ n. v - ' g% I$ Q8 |! l$ J% N! U# t( L
) C+ Z m a0 Z7 ^/ m) Y7 _& X+ j- v- public bool IsReusable
0 Z, H% L) W- s0 M$ r& G1 r8 q7 q' Z - {
) t$ b6 h0 ^- z6 y7 R1 \ - get3 {2 x+ W) a3 O% Q+ P9 [* \+ g* m
- {
! Z3 F0 k$ m& ~$ } O6 f @/ ] - return false;. C4 t! Q) W* O9 Z1 P: [
- }% P( q; p8 \* w$ F- e. A
- }
: G7 q% X1 O3 R% D+ C - }
% Z7 A- o' N7 z; F1 z - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 : h8 w) S, U7 p+ d6 u
|