|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
1 \5 b C; S& x6 x, r$ p5 N4 U2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
% L! k& R' b3 L0 O; {- W% B ] - using System.Collections.Generic;
- }* i9 U5 O% R9 ^& O' S) R - using System.Linq;* L5 e1 d/ v# z! M; S. I3 e- {
- using System.Net.WebSockets;( M5 {8 j" h$ t X$ I8 E5 f" ?
- using System.Text;1 _4 `5 z) P- u! W0 ~
- using System.Threading;
# T: J( e9 f. _5 _ - using System.Threading.Tasks;$ Q9 O1 | I! p7 n% H0 A# }
- using System.Web;- X. P, X& [- }0 Q& P2 {
- using System.Web.WebSockets;0 V. G0 H# W ?" V, `9 t1 R* R
- 6 K$ v' V2 L, C" g
( G( P" N9 f4 `/ }) A4 y1 `( J- namespace WebApplicationWebsocketHandler
+ ~. `. i, I; D9 v7 x0 i a3 `, B' A - {% e" o; b0 P: P! o) ~3 B! C$ ?. Z
- /// <summary>
7 e# p" [( {. U4 V - /// 离线消息
' Q* |# _; Z- E# X; n4 O- n+ J9 _ - /// </summary>
; A0 ^6 I. r$ W5 r; `5 ^8 N - public class MessageInfo1 }4 R, Q+ n# `! Q: F$ x/ l) `
- {
) b2 D5 O& X2 n! p - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)4 x- x' P( h% `: P3 w0 a
- {3 J: {* l M4 s
- MsgTime = _MsgTime;6 P+ r2 v F, l9 E1 r
- MsgContent = _MsgContent;
8 D) \* T. u0 ^1 m7 v- {+ u1 | - } {7 `/ m+ O& x0 |& u* j
- public DateTime MsgTime { get; set; }/ w& D( @% p4 b2 d J9 d3 I9 e, t( v6 m
- public ArraySegment<byte> MsgContent { get; set; }
& h6 g5 ~) D+ n2 ?0 @5 p - }; z9 e+ w2 k( i
- 9 N( X# [. R+ S) C: b' z* d# ^. H
* _! ]; Q! F' [% t3 u+ ~/ f) I- $ t7 G d) _2 `! b* n# ~6 ~9 \! s
: k N$ C! q# T' x/ d- /// <summary>
4 \, q" H( a) E- W - /// Handler1 的摘要说明7 l) O8 U5 r F; @5 r. H
- /// </summary>3 O4 h! @9 P, o" o, `
- public class Handler1 : IHttpHandler# k! F5 E# R- e* Q; E
- {* ?( b1 X/ \& ^! D: a2 R8 X
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池$ r) y6 ^$ @- W) y# ]
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池( H# D* h; [& x& \
- public void ProcessRequest(HttpContext context)( ~/ p3 o# F2 ?3 W
- {
7 t" s6 ?) a; M) I - //context.Response.ContentType = "text/plain";) U% C0 T- G0 X6 m5 H
- //context.Response.Write("Hello World");7 y7 h0 [4 J* ^7 c7 o
- if (context.IsWebSocketRequest)
! W( I: v, S7 H - {2 t, P( N8 |. e+ q
- context.AcceptWebSocketRequest(ProcessChat);
) V, c2 {7 C/ ~7 i( _* V - } 1 z% {% M6 ]2 o& ?0 H) v- v
- }
3 B3 B% Z% w9 ?$ G8 o2 r
8 q! c; u6 p" k- private async Task ProcessChat(AspNetWebSocketContext context)
# ]% I4 f {3 e1 g/ }# v% i/ u - {
3 X3 |0 \# @& f: @& q( s3 G - WebSocket socket = context.WebSocket;
* y- D Q0 S" [$ G: C - string user = context.QueryString["user"].ToString();) Y$ P0 R- K- ~/ K( |
- & a3 f6 t% s( n0 |: Z4 A9 `" _
- try
' e* j) J( y0 A; u3 u6 S - {
L0 t8 v8 T" { - #region 用户添加连接池
* D6 a( P: ]7 q0 i - //第一次open时,添加到连接池中6 Q: V O* R8 {7 Z
- if (!CONNECT_POOL.ContainsKey(user))
4 m; D. c! }3 \$ @% ]) p' c - CONNECT_POOL.Add(user, socket);//不存在,添加
" }3 o# G6 {! H, ^ - else9 f+ l/ g9 X& ?1 z! R3 G
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新4 ^7 E6 H5 f6 G/ q
- CONNECT_POOL[user] = socket;
' Z4 Z! t. d0 R3 M. }4 H8 \ s - #endregion* @6 S. H( z! T. _( f; n* C( j
- - V& o" t1 ]0 @# l; S
- #region 离线消息处理4 A2 g9 r: `" ]4 V
- if (MESSAGE_POOL.ContainsKey(user))
7 K9 e- c/ X7 K( {7 r9 G - {
" R: Q' N- @; i* }( p - List<MessageInfo> msgs = MESSAGE_POOL[user];
; D0 `1 K7 u4 H* B/ x - foreach (MessageInfo item in msgs)% ?7 {2 v4 S% Y5 v+ k0 p4 `
- {
+ F P" j3 h+ h. M - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);/ `% k i" f# Z8 k, H, Z
- }
, _6 ]( l( Z* Y: O" X+ i - MESSAGE_POOL.Remove(user);//移除离线消息
1 J4 e. Q( R8 B& F - }
2 @: I; J7 H2 w! u - #endregion
2 F; O& s: u9 _
6 T0 `8 ~8 H9 U, U9 J- string descUser = string.Empty;//目的用户
' y* D& O$ W: F - while (true)8 U8 d# \( {9 j& \2 {: u
- {
; q1 n1 D1 P; E" d - if (socket.State == WebSocketState.Open)# a1 D+ p* @) u2 v# u) i
- {3 t& U" W L; \
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);; a M* D) |6 p; U3 ?5 B" i* B
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);& G7 M* h; w5 u: J
- , y7 F* I9 d# p0 C) Q( i" T* P
- #region 消息处理(字符截取、消息转发)& c3 N/ S6 N$ R6 B3 A2 n
- try
& H$ s& ~. g& c% P- W! b, Z3 X' h - {
4 `7 v- c5 A9 d1 N& Y0 \5 S - #region 关闭Socket处理,删除连接池1 E* P! w; Y! g" V' L
- if (socket.State != WebSocketState.Open)//连接关闭/ I& s' w* `: V2 n2 ]+ V
- {) T: ^& J6 b/ A! k6 o
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
1 B! r% m* q! o, Z5 a, l: q' B) x - break;
7 p7 E s5 S" W; O7 |5 N p - }
4 s+ b4 X* ^$ k7 C% {+ T - #endregion
. U/ B8 I! X5 @' D3 ], B2 l: l - ) g- \; a8 u/ i
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
6 x# [8 u' q7 U+ W9 q - string[] msgList = userMsg.Split('|');
: n0 n- b1 g! o; N - if (msgList.Length == 2)
' |! k" G# s4 X) R1 _ d - {
( {$ {' x8 Z: Y5 Y; D, \1 T - if (msgList[0].Trim().Length > 0)
; r! D, n& V, \$ @1 q - descUser = msgList[0].Trim();//记录消息目的用户
$ N, {. v: r# Y; P - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));$ f( M- {) J5 a5 f
- } }1 j# h; L. v. s6 W( i
- else; l1 K& [5 u* m) N2 M8 A
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
5 `# w5 U' j# a2 E
8 s2 ^& z0 e3 Q0 W) U1 f% i- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线/ S1 J" J$ z# a& y/ B5 {# o- W
- {
3 \: s+ i6 i; C0 S: P b% o - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
9 {3 [1 ]2 J1 }! @ Q9 E: @ - if (destSocket != null && destSocket.State == WebSocketState.Open)
( j0 R0 `! `; u& S# @& R8 W - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
: W+ `( {. e5 Y5 ~; V - }9 F7 I' S4 k; j8 f! [- k% [
- else a4 y+ M. Q, j
- {* ^2 h/ }$ m. |" k' P) q' i
- Task.Run(() =>" g* b _; n8 ~ x9 _5 Y- |
- {2 e0 K! Z! K! l% T. Y$ Q6 i0 [
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
\5 v$ n9 s- e6 q A5 d - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());; r( n7 { p9 I, i2 e# P/ E a/ f& J" b1 f
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息1 U6 y3 y* j: V' P
- });
% b a7 @ f. x# y3 j' P - }+ K) x8 f3 {6 L
- }- |+ G1 E3 Q# L2 U5 ?6 z
- catch (Exception exs)
) n) H$ C1 M! E2 ?$ c - {
7 l+ X. i! T( b% `6 J" N, H - //消息转发异常处理,本次消息忽略 继续监听接下来的消息( D: W* P7 a8 G# \* i. z" Z
- }
' U: n- t, Z$ x' s% Z. W3 f R - #endregion
- Y0 ^0 T: E2 v1 D" _3 x2 E - }
2 ^, u* e. t' O, n - else
: E) S" N% E) m+ |: X0 T9 H - {6 ~2 p) B! G/ a
- break;
' m: U/ h" A' V* E9 I - }4 g2 x; X& n: V2 s; R' y2 F
- }//while end$ H* q# z( n8 w% E+ ?% m
- }2 R6 M- V3 z4 K8 i/ f
- catch (Exception ex)
) b/ ~. L# P1 ` - {: M8 b3 u S0 H7 k/ e e+ [+ y
- //整体异常处理
9 J# y R9 v! V/ W- ? - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
) p: \# R/ H! l9 r; T5 W - }
5 ^( c- p0 h& v% ~ - }$ h. J/ n/ W2 @/ N
! P! H$ k2 s- H' Q- / N) y( m; _' s X( N
- public bool IsReusable
' A5 P) E) G+ ^5 s9 A6 E" d - {
% R% g: G+ f3 ~# t" ^ - get
9 B0 ]: i# z ~- o4 p+ b - {" ~$ } n* H: i8 Z4 ^
- return false;: }4 W) U& b) J/ q
- }
- n9 O8 }* b& E' U$ p - }
% G- L6 V+ S0 t& U9 ]- m - }
. K/ ?' l( ^2 {+ i - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 ; a( ^* _ i6 E: S% E5 ~. F" R
|