服务器端代码编写 1.新建一个ASP.net Web MVC5项目 & K- S+ Z3 b9 ]) U( _* e
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;# w$ q3 h W: H- d- |
- using System.Collections.Generic;
1 q. d- m( [1 T" M X3 X$ f! [ - using System.Linq;( }" F4 E5 K2 N/ ~7 a
- using System.Net.WebSockets;
- D. J* m, D+ e, O3 u - using System.Text;; q) R3 w/ S5 n+ w, t4 h5 x2 p
- using System.Threading;$ T8 @+ L9 ^& z8 K' \& @+ Q+ p
- using System.Threading.Tasks;4 P( o) H- @# F: Y% T4 v
- using System.Web;" S! K1 _& s. c, _0 `2 u
- using System.Web.WebSockets;+ U( y) `* |1 l' Z
- - u9 s3 Y: |2 P W. O5 S! F; t5 C9 \
8 K; n8 H5 C$ Z1 v7 |6 H5 R( b- namespace WebApplicationWebsocketHandler
& m+ Y2 V3 X9 Q2 F% Q& @ - {0 V4 E- L4 s; h0 H% F0 _& {
- /// <summary>
w4 @' ~; n7 m1 q& p - /// 离线消息
$ N. B5 ^/ j$ U' y - /// </summary>
* s7 Q8 F& c$ Y8 A - public class MessageInfo
( B' X6 Q T I# n. G2 P( V) u - {
% t5 i( J7 J$ m - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
3 c- P7 K1 d- }+ H - {5 _( s1 m. l& f# S; t
- MsgTime = _MsgTime;$ K3 G0 s6 u- m* E
- MsgContent = _MsgContent;
7 E- x! B- m8 |/ O0 g2 l- p - }
; u( q8 X3 e8 O2 h; _, X% L6 P - public DateTime MsgTime { get; set; }0 ~3 @: B; g! B, u
- public ArraySegment<byte> MsgContent { get; set; }
+ a. @7 S/ {1 T0 |# w: n& g - }; r+ C1 D) @7 x+ g2 c
3 e% v& @, O: s- 0 {: v7 d5 f& Z' x- F5 m6 o
- 7 e! F! L6 Z+ w
$ O( u1 P5 _0 `+ c1 K9 P- /// <summary>& r2 ?3 [+ T3 Y- p
- /// Handler1 的摘要说明) m, U& j; F% a. W, I' {
- /// </summary> h2 u9 ^; `' U" b1 y. N
- public class Handler1 : IHttpHandler; y' b9 U7 k, O( }% l, E* b
- {
- v: _& B5 Z& i2 E6 M; b - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
6 v+ A' [1 o9 g - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
( X ]( J$ P7 ? - public void ProcessRequest(HttpContext context)
V+ G; u2 J1 a9 x# o - {
$ ~4 _* K8 a+ A, K - //context.Response.ContentType = "text/plain";
+ E/ f/ A$ k0 h4 L/ l7 y3 x2 c - //context.Response.Write("Hello World");
: z5 _5 I/ L, s( ]- G4 D* l - if (context.IsWebSocketRequest); r, p7 P% B" N
- {
7 q+ P. E# Y3 \" y1 v0 C$ v - context.AcceptWebSocketRequest(ProcessChat);8 t1 p1 v6 f o: W5 a3 P4 ?
- } ?+ V5 L5 H# R2 k2 I$ k9 E; C
- }& E9 ~ ^- H4 R$ ]& n9 u
- ; D d% R; u4 B% r$ S, X
- private async Task ProcessChat(AspNetWebSocketContext context)
! ^& y, R& d+ k9 W9 m9 x( v' g* T - {
* [# a% d/ F$ l2 m0 D# R% m - WebSocket socket = context.WebSocket;
( H7 J8 D) I) `9 x. c - string user = context.QueryString["user"].ToString();: a% L( Z" F! e: O" U. X/ ?
- ' c3 `6 D% N$ F7 ^3 j
- try5 j2 _+ W7 ^6 u8 P( X
- {8 v) r" M% j- _$ |( M) ~+ r
- #region 用户添加连接池
8 m& @9 G9 X! S! T - //第一次open时,添加到连接池中; Y+ K: E% f8 S- _) s
- if (!CONNECT_POOL.ContainsKey(user))) C' L& G8 G* t
- CONNECT_POOL.Add(user, socket);//不存在,添加
8 c2 ]* p0 v$ H7 d2 |, r+ D+ r - else
4 {2 [- I" e! H% ^. m& H - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
1 X2 @6 G5 _& F9 H2 r - CONNECT_POOL[user] = socket;; @, M+ Z. z% A. q- e, Y( i' S( n
- #endregion, |, w: ?* D) i3 D/ s! l, G
4 s [& g5 X0 {! F; s+ V ?1 l' K) E6 t- #region 离线消息处理+ z9 f, ^1 a; `9 Q
- if (MESSAGE_POOL.ContainsKey(user))7 j5 m! M3 Q$ m/ O! c( U. ~6 _
- {
1 f. i4 E' u; p/ ~' B - List<MessageInfo> msgs = MESSAGE_POOL[user];
/ x }2 F( V# ? - foreach (MessageInfo item in msgs)) K% p- L r" n, y
- {
' ^$ f/ H4 |( t8 @ - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);' [: H+ o) w B5 G
- }
3 M3 N" l2 q" D+ A - MESSAGE_POOL.Remove(user);//移除离线消息
7 m; q7 a4 Z9 D) X+ g' U - }0 i7 K0 @% t! Q/ }2 C
- #endregion ^/ r) G. y$ a1 u$ k
- / H( t9 @, ?6 E
- string descUser = string.Empty;//目的用户 [- E5 i; y3 a8 |' Y* v8 a1 c9 A
- while (true)
6 F, n r5 L4 t0 m. y0 x/ `) } - {3 f( {3 L7 U4 R( N& D- u; Z
- if (socket.State == WebSocketState.Open)
2 ~) U9 J1 m; j S% F - {
7 j8 z+ T- H- ~1 |$ h - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
: `6 D/ Y9 }' }$ q4 j2 | - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
+ h" ]/ |! |1 u b( l - C. S( X6 l/ v0 x% M U
- #region 消息处理(字符截取、消息转发)
) o1 y9 e* z' K# u - try1 k/ \; D; X- [1 H0 ?' Z6 q
- {
$ k/ j5 m3 T9 c$ E - #region 关闭Socket处理,删除连接池
$ y3 o" z# t" y3 ?3 s - if (socket.State != WebSocketState.Open)//连接关闭4 t5 V k& [* N( F* q) Z
- {
* I; l7 a9 K' N1 e, L0 j) \6 c# c6 I - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池6 O. v2 `* D% X* g7 `' e
- break;' y J1 X( b0 B4 `
- }
" s4 p; j9 k+ n% \" @8 a - #endregion2 u- x( a# b# J$ L; j8 j3 c$ z
, q% Q @- V5 v6 j/ n- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
3 p5 j+ C6 X4 o& Z `! U - string[] msgList = userMsg.Split('|');
6 W2 O+ ]+ Y1 z! u# e, c - if (msgList.Length == 2)7 x5 m1 H! F( Z7 b* `3 O; n
- {) h' `/ n: Y; n, A; l
- if (msgList[0].Trim().Length > 0); C) ~7 T$ {# c0 s
- descUser = msgList[0].Trim();//记录消息目的用户
7 D/ X$ B3 M" t4 J) B - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));5 k2 U* k6 y( f8 |
- }
9 Q* S5 K N/ I" b3 V - else5 g" k: h# q2 V8 O3 x" k, E
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));/ Q) w, S r. d, Q% `7 _
) J$ h) C o4 A( ?- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线! f" s* u$ G6 |5 z& }
- {
0 z1 d6 j" t- l1 [9 R+ ] - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
1 G6 w* N5 B# m9 t2 o - if (destSocket != null && destSocket.State == WebSocketState.Open)
5 b, Q/ b$ Z& ^8 Y; v - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
! o, Q2 d) W) w7 O T - }8 j+ ?5 ]! _1 J
- else" i* C. D7 |/ ~9 C: c6 v% C* o4 \9 B$ v
- {
6 k- J1 ]+ v6 k3 S - Task.Run(() =>
6 e8 P- c9 h$ _; ^/ } - {
% Z+ W1 y! ^+ B - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
. A* u$ h- z% w* A3 a7 _3 O - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());) v* D9 }% N+ ]
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息$ T$ r$ E( U" Y6 a( }
- });" `7 A0 X( U! W6 p9 O5 \
- }% g) D9 Q) u3 G/ P8 \
- }4 [& ^7 m/ J6 s- |
- catch (Exception exs)
$ d t+ m6 Z9 L4 ^" p6 ^# [ - {
1 N! m$ [: ]) _: o, l - //消息转发异常处理,本次消息忽略 继续监听接下来的消息# h* z- t0 { c- j
- }
" _# P- u0 p5 N$ y - #endregion
7 t# K# g) Z& \& I% `6 r - }
( p9 V2 ^* Q2 D2 j/ ?" | - else
* h5 s7 Z4 `- }3 L - {
S7 ?8 \% @! g: _ - break;
4 b0 ~5 a3 S$ W# K - }) t9 p0 A" W2 S+ z
- }//while end
2 a3 f- K) a3 \5 V - }
( b' x% z2 i5 H$ K - catch (Exception ex): D4 o; F7 f0 U3 l
- {, ~# s3 F5 }7 g) N
- //整体异常处理
+ R* x1 Q7 R+ H- U H" u - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);! o3 R1 y/ F o5 w: u. W! C! C4 X
- }
& z! d4 O. t4 [' z - }
4 B( d$ N! C; K& [/ K
7 u7 x6 I: j0 n7 a; ^) r9 o
0 ?0 A* O1 [9 q4 X/ a) C! d- public bool IsReusable, D! k; ~( d" h
- {
! O+ y+ k& Y2 x% ?0 Z - get
1 h2 R6 {1 ?0 O3 a6 ~ - {
# D' F E. t. \7 p+ e - return false;
0 w3 p+ T) K: n9 Y& [: X. j3 M - }$ Q4 [& L2 n2 z1 X# V+ I$ z6 ?% s( \% k
- }
* R0 S& A& I5 r; x& Y - }3 f4 }6 i; n6 t. f6 L% a, R" r
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 - L+ x0 S7 Q+ _1 Z. \6 k9 W
|