|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
* r7 I5 g/ a' i0 F# k* F2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;0 s R; e7 h% r# n4 S
- using System.Collections.Generic;* Y' x! f% {6 M9 W/ H5 o# T
- using System.Linq;
. i& N! ]* c# b' W; N - using System.Net.WebSockets;
$ }+ O8 t5 h- a% P - using System.Text;2 D, X# S) J. O, ?- V
- using System.Threading;" f1 f6 }( D7 j* {, _" Q' j! _
- using System.Threading.Tasks;
" G1 G; _. c, n4 q7 s% R" k - using System.Web;
4 S$ a; Q% k" P" k* `, j - using System.Web.WebSockets;- A: c) E$ R9 D3 d3 k& x2 c
- + n3 [3 }( ~1 a9 [' x
- + H; V! v2 m- b& m+ w1 e) k
- namespace WebApplicationWebsocketHandler
, |! A2 V Z4 |" `5 ^( I9 f" R - {
0 C* T; n* M1 ~# k* g0 } t" V - /// <summary>% G, ^) f5 G1 o6 N i9 Q
- /// 离线消息) U0 E+ Z1 b5 n* T
- /// </summary>9 v9 J' x$ d% v0 O! Y3 c |
- public class MessageInfo
\9 ?9 B/ |4 X0 `0 K) X/ p2 d - {
) K, O* z0 b% W# a$ ^ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)0 p/ s7 u `8 n) D2 c& S, n
- {
+ [' A( @* D, D3 o - MsgTime = _MsgTime; o. v% `% i' S. L/ o
- MsgContent = _MsgContent;) @& E1 L! v: G" j- g8 H
- }7 f8 o- l) `0 p5 i& @2 Y. t
- public DateTime MsgTime { get; set; }& q- W h+ g0 p* Q( _
- public ArraySegment<byte> MsgContent { get; set; }, \1 v& r1 g7 k y( f0 K& ?
- }* B) N' H1 x2 p# c e: R
- - }8 g4 k. {( W! j N3 J, Z
* T ^* c+ g5 w( S, n( s( h
! ^' _* ?0 Q5 f3 G' ^+ ~/ i! |0 m/ y! \
) T+ K0 t& {4 l3 o; U; G- /// <summary>
9 c2 E6 S# H) V' H - /// Handler1 的摘要说明
9 @9 k& W! K& [0 S X" t5 \ - /// </summary>
" P7 I4 \+ e# c( ~9 `9 N$ e0 d v - public class Handler1 : IHttpHandler" R! k% M. B1 i3 f
- {% w8 W# G' l: A* X/ ^1 w! c" G I
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池$ v* h, @( ~0 u6 x- c
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
" E3 U$ y: x7 H# u) y- Z - public void ProcessRequest(HttpContext context)( i5 b% v5 i' K6 B2 J5 `2 l
- {
! ?1 F1 e: K: X - //context.Response.ContentType = "text/plain";; }" }2 F7 n% t; p' j" ^: ]
- //context.Response.Write("Hello World");* V: K* ?: ]& L8 O
- if (context.IsWebSocketRequest)
( c' W8 O" ]; N ~8 n6 d - {
. C' w0 F( W& R - context.AcceptWebSocketRequest(ProcessChat);2 K0 f& ]2 F/ s; x/ K! Q
- }
3 {9 ?) K7 _' \( ]$ e5 R8 T$ P/ o - }
. n4 Z' K* W, w- g: } c4 F* g
% J |# O2 |9 g- private async Task ProcessChat(AspNetWebSocketContext context)% J4 B R4 ]. {- ~: T; R
- {/ k* B9 M4 ~+ Y( d
- WebSocket socket = context.WebSocket;
5 w, a: e" } ~ - string user = context.QueryString["user"].ToString();' [ \8 l. Z% x
- 4 f2 O+ E# q: L/ y
- try( r0 Y3 S, q. a8 F) m1 R6 K; g3 O7 p
- {
1 w9 g+ e/ X! Y1 j( ~/ @ - #region 用户添加连接池
" C# Y8 F J1 s) f - //第一次open时,添加到连接池中
; N' ]; {4 Y L3 h - if (!CONNECT_POOL.ContainsKey(user)). c4 D, B4 l! L
- CONNECT_POOL.Add(user, socket);//不存在,添加
6 _: n) a a% ^ - else
3 h; c+ Z" I$ N$ |; L - if (socket != CONNECT_POOL[user])//当前对象不一致,更新5 j- c' J8 L* L
- CONNECT_POOL[user] = socket;
5 b% t6 h' T: n0 Q8 y$ p - #endregion
. B$ A7 k5 s4 B( ? - . S( G7 T$ ?6 E4 R& Y8 a
- #region 离线消息处理2 c, _$ d6 ~) ^& F2 x
- if (MESSAGE_POOL.ContainsKey(user))
' {0 C7 h4 r7 X, u/ \ - {
$ o; Q" I3 ?7 B4 i* X - List<MessageInfo> msgs = MESSAGE_POOL[user];
+ p" i- \* t4 B, `/ B - foreach (MessageInfo item in msgs)6 u/ t# Z6 @6 p( Y! {6 M; X; B
- {8 Y# ?) e. @4 I! L7 E. W6 H
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);8 J1 H. f/ I5 u& M4 a
- }3 r$ g3 ?$ \( M4 x1 Q8 T0 ]
- MESSAGE_POOL.Remove(user);//移除离线消息% a& B+ n* m& P$ o
- }
. J6 }5 \+ w( ^9 Z5 l - #endregion
% L/ Y) t) M1 T+ e6 _ - ; q& X0 h# S6 v( j: n( p
- string descUser = string.Empty;//目的用户
4 _# }: m6 m k0 D/ z8 t4 Y - while (true)
$ O; |6 l. P9 M) s - {
& b3 m% N1 N& H3 f; p( X6 M% n - if (socket.State == WebSocketState.Open): T' A8 h8 Q+ ]/ H
- {
' R8 a$ J. P1 t; n - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);5 }3 k# P& s+ y
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
, W" e* { a) x5 r% i' z/ s. H; x
" b; Z7 Q# ` t: E2 o- #region 消息处理(字符截取、消息转发)5 e/ o5 f6 w: ]. D6 S R
- try, ?# F0 Q" N* Q0 Z* H& w) w
- {
/ }5 e1 h c k! F5 M/ ] - #region 关闭Socket处理,删除连接池
# x$ A: s/ Z! v" V7 N - if (socket.State != WebSocketState.Open)//连接关闭
) h9 L4 P, j/ l - {
! z' _ v6 ~0 {9 v1 v; B - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
: N9 P6 r, E1 Y9 j - break;0 q: q( @. \0 i, H8 V6 q
- }; U) C7 S1 N# J7 q! f
- #endregion3 c# ^: m( h1 P; R
- w( k$ a) F" G. V- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
' F7 N. V4 N6 ?0 E$ J: G - string[] msgList = userMsg.Split('|');5 W# f* c: F; |3 U6 K
- if (msgList.Length == 2)) ~7 J( [1 C4 @, v. K0 r
- {
3 A2 a4 L; Q* I/ T. I - if (msgList[0].Trim().Length > 0)
! M: h# L' Z* p! _1 Y - descUser = msgList[0].Trim();//记录消息目的用户
9 n' ? Y; Z* Z+ Z7 U* ^9 [0 ?# @ - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));+ K3 d0 G* @/ e
- }
' Y/ a- d3 }: u. e - else
% ~0 }& b1 y/ x; j% b - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
3 d- g( U. a2 v0 D" F
% O: T, G' F: Q; C- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线% y# X" S) V% D: F9 O3 X) M4 z
- {
! X* {' A) N1 C( X2 B. } - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端1 D n1 |2 r7 d; S+ P" \6 S. W G
- if (destSocket != null && destSocket.State == WebSocketState.Open)5 P' C& u3 J/ ]# @
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
( @3 D2 O' K' V& U! V; } - }
0 `8 ~9 i) g2 a$ _+ P - else, U4 K! H3 f& l/ s; x8 {
- { |/ z/ s5 S: [3 Z$ p: {" M
- Task.Run(() =>
/ r t- \& \6 C. V - {
4 K0 j& h% k0 W, P7 B - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
6 o7 {( ]7 e4 m2 U5 r - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());5 d1 _ p* j5 u
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
) Z2 a' e0 Q% L0 d - });. A6 m/ n; d0 p- Y& o$ I" \: o
- }
5 m; c) ^0 W2 D: f3 { - }0 A( v* d' Z5 g, i I* s2 F
- catch (Exception exs)
- f# g. z6 U' x, v% ]5 t8 e# t& V - {
4 ~' Q& I; K. J; ?3 j2 [6 f - //消息转发异常处理,本次消息忽略 继续监听接下来的消息. u) ` I [ X
- }0 m9 a. c* o' U+ `
- #endregion
9 B- f5 V( l# n - }2 J1 N, D: g% \/ Y& q( g" d9 {. h
- else
9 a1 w m5 {( ^0 N9 r: g - {* d. R {6 V& O+ Q! J
- break;
: j+ v( e6 Q* \, {$ H9 n) t - }" b$ x4 a/ V" j- Z. C" N
- }//while end
# M: [4 }/ C) s% J# ]6 B# O2 Z$ E - }; Y9 V5 v* ^; \4 t2 k" o/ G
- catch (Exception ex)
9 {0 u& o1 G, B, i4 K - {
6 \5 j6 W; G1 r3 o4 u6 d8 t - //整体异常处理
: ?3 G7 u9 o; ?8 k% e$ h( t6 c - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);- P8 s- M2 Y# t
- }
# A' K" X3 c6 |) n- K) U" w- m, g, o - }
/ s, U1 H4 G$ B' f/ C+ ^: _ - % _4 R' W% T* Z8 p+ H
- ( r9 t% @( ~% O% T% i
- public bool IsReusable, j3 V$ r! w9 O2 k) s
- {
* {& x' E0 g n8 f5 j- ~, F - get
' [0 g5 I% \7 Y( M @( @- O6 @2 H - {
# s n! j5 Z6 V3 P2 T& Q - return false;+ u) X+ \6 ~: ^" R$ Q- y
- }( w5 m! j) p. s# T$ R W
- }7 V# m0 e, d( \: ?% X: N
- }
( J; I; S9 D! @ - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 ( W2 X e- {9 u& g% C6 @- U" M
|