|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 2 e _3 Q2 m0 f% }0 a+ c7 {
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;$ G" I3 D( |# Z& G) H
- using System.Collections.Generic;
$ P( B6 N6 c& n - using System.Linq;
$ a6 P0 S, W& j8 ]6 _ - using System.Net.WebSockets;: O0 G7 Z" P, ~6 t0 V$ @
- using System.Text;
) U: b/ Y- R" ~$ t6 h - using System.Threading;
2 C2 r0 b" M4 u( k - using System.Threading.Tasks;5 B1 D9 B n+ D# k) e! z- G
- using System.Web;
- |- v+ \, K& t - using System.Web.WebSockets;2 F+ V3 @8 g1 `; [
- # m1 w& d5 o ]1 A: @* y/ ~- @
# ^: x, D/ \/ E$ J6 a' S9 a- namespace WebApplicationWebsocketHandler! K) y: t4 J: Z, i/ M& v
- {: y5 p+ n, ]/ T: w( F
- /// <summary>' E, I$ k0 T/ u- U& A9 l8 r
- /// 离线消息
) h9 M. Q+ l' H2 K - /// </summary>7 k6 }( J# a9 T/ U7 T4 I8 N
- public class MessageInfo9 W e" F# [, Z( J
- {
7 I! V( D2 a2 \ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)8 ~& F: ]+ Q- Z* _# C2 X( V
- {' a; l$ M$ v3 V! C1 o R! \
- MsgTime = _MsgTime;. b4 } X6 D5 ?( Q: G
- MsgContent = _MsgContent;
1 |% z. N, F& U0 j - }, p6 c% G/ I% [4 h# b6 E
- public DateTime MsgTime { get; set; }
& g% m+ l% c, T! M& y - public ArraySegment<byte> MsgContent { get; set; }' B- }* T# r o, B
- }
* Y' H! L( j4 M6 a! i% I* _ - - |1 G: k! J1 m. g+ H# x. {
$ W2 u# g. \- X0 n
4 [! Y6 u' A- d$ `$ D" ?. X- . x* M' M, ~6 }2 E5 u
- /// <summary>
; r; z: V& [9 e. S - /// Handler1 的摘要说明
6 R& t2 C9 f8 f( \* d - /// </summary>
" W( U/ Y. F3 R* y7 W - public class Handler1 : IHttpHandler+ L a3 a* ^9 M: x
- {( I' r/ ]9 ~ I1 U. L. K$ Z
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池0 w) Y* f7 Y. [* [ ]
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
+ d% G- ~; @& V |, T# N - public void ProcessRequest(HttpContext context)5 M; o H! ^$ U" `( T
- {
6 O( }: G8 G7 y/ l/ @: W. u8 t - //context.Response.ContentType = "text/plain";- _/ G. T; F; B: G* S Z
- //context.Response.Write("Hello World");# h8 e' s+ b. }5 }" v
- if (context.IsWebSocketRequest)
1 O7 `+ r- d" D& X, ` - {
3 Z$ Q5 W' o& p9 [- u) h' a. l3 U - context.AcceptWebSocketRequest(ProcessChat);
5 c5 O+ K, U- f( r" ?+ ~: {' v - }
% v' n0 E+ j, ?0 v - }+ b( r9 N! j# |# Z1 ^
! K4 h1 A6 i' s) z+ ?& {! O- private async Task ProcessChat(AspNetWebSocketContext context); h% ?) J! ?+ H4 Z' S+ g+ i: u
- {( A+ n8 ~ D0 f
- WebSocket socket = context.WebSocket;
! n* O1 I5 U* \9 P - string user = context.QueryString["user"].ToString();
) V8 M+ Q: X% P" V% A; ~/ E - 3 b3 x) F. U3 T/ _( Z: K
- try( p3 P/ s) X5 B0 r3 H# }# D- U
- {
v' }% @3 J" e0 R4 Z( k, b# E - #region 用户添加连接池
( w0 F `6 T5 S. d- r2 v5 c1 I - //第一次open时,添加到连接池中
7 Z) ~9 t$ N' s: O' B. ? - if (!CONNECT_POOL.ContainsKey(user))
8 u/ k5 F7 e2 S" Z6 o% ~ - CONNECT_POOL.Add(user, socket);//不存在,添加
* z: l' o: R. j& ]$ Y& _ - else
5 f( t7 J3 d9 N0 N% k# c# g - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
) K% r3 A4 j6 M8 W/ e: o - CONNECT_POOL[user] = socket;
! _/ B5 E W5 G/ b- n% ] - #endregion4 g" Q. k% p. @) |
- $ A" O' B- I A: x# g
- #region 离线消息处理1 p4 D; ^9 ^! h/ d; l# {# a5 N
- if (MESSAGE_POOL.ContainsKey(user))
3 }/ Q6 s0 Z4 Y8 F5 B - {
3 l2 Q. U7 k9 p ?6 Y" X - List<MessageInfo> msgs = MESSAGE_POOL[user];
7 x% q) p, R2 L8 [- I) u - foreach (MessageInfo item in msgs)2 ]. `6 n7 q" f! u D' u. C% f
- {; w7 O0 u3 }" X, s* F* J! l4 Q) y+ L- F
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);" F9 A0 g/ _% n6 B! X/ j8 X' f
- }: }% O0 f0 R) D$ S+ H
- MESSAGE_POOL.Remove(user);//移除离线消息9 B& \6 C% D# {7 P# z1 }0 Q
- }
) ]5 Z& o( q- E7 i( v# ]* \! C - #endregion
+ N h: d6 p' o% r" g6 ?* `
* L# A$ p& v4 n5 C; ] L- string descUser = string.Empty;//目的用户3 F2 F9 r: y: ?% M% x/ t, v
- while (true)
5 @4 w& }7 b% E& O, ]8 _! y2 c - {6 B: q% K, n) S1 Z# g7 [: _
- if (socket.State == WebSocketState.Open)
% v1 V+ G( }& F; a2 Z2 l - {
. A3 g- B5 M5 J; D3 U7 E2 c( v - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);0 ~0 Z) g: ]7 V
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
- V. U; n" [) H/ G% I/ D5 u5 v - 2 N4 x! ]7 \3 x! I
- #region 消息处理(字符截取、消息转发). r+ z m& E+ w) [ w D
- try/ z$ P3 ?: H) C
- {' P. N6 [9 s) \3 ]$ `
- #region 关闭Socket处理,删除连接池% _, Z7 P4 z! n( p% ?( p) s
- if (socket.State != WebSocketState.Open)//连接关闭
( V: w) `3 \9 Y, q7 U3 c+ z - {7 d" S) g0 v7 t) o0 Y
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池7 _ I/ ^9 B" R$ w& h3 q
- break;
" Z' [ W" S2 N8 \3 ] - }
* H$ B' ?$ m1 n - #endregion/ f; @( G9 f- V
- + w% m& K! N- ?% l; j
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息$ s; w& L9 {/ [" k. F1 U
- string[] msgList = userMsg.Split('|');
+ ~& q8 [! W' B U1 E; A @ g0 f - if (msgList.Length == 2)0 f' Y/ ~* v$ v6 n8 z( P" ?
- {
" u; n M6 ~7 j$ S7 l, p, d/ f! Z - if (msgList[0].Trim().Length > 0)" d' t* f1 M+ g- J; N
- descUser = msgList[0].Trim();//记录消息目的用户
+ G: ]+ x3 N, d- n+ w3 ]0 k - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));+ J8 c w S$ M0 L3 B
- }. b9 }" t! `* s8 z0 _. y7 f0 G
- else
: _7 q! F$ U5 ]% x- c - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));, [6 C! t$ @+ n. E; H/ }; ]
- * R5 K1 F. t# x
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
" j+ V5 E! R6 L) D - {* H$ q. W0 I" t: W) y! A: J
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端! ?, G4 o$ Z0 w# y# A8 F
- if (destSocket != null && destSocket.State == WebSocketState.Open)
: @( c1 F) {& Y, e& i - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
5 m* Z8 [4 z2 `$ v - }
- W4 q, J$ f4 \0 A - else
. V3 {3 n1 T" N( g2 c+ O - {
3 s- I8 x6 q7 n; _: E! N5 I. h$ v - Task.Run(() =>
6 T3 u4 H$ V" @# Q; D1 R" [# K - {
9 O( O( F) w& J8 x - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
+ i& M7 O, Z! a3 f- ` - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());9 K; A a) N# |1 t
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
% P3 N5 X6 C ?! V - });
# J& i. f2 c0 j( J+ _; H( f; d9 C& w - }
" N: n+ k Y" }& g- Z# g0 M9 q- D - }8 N- @ x( C& k$ k
- catch (Exception exs)$ @/ w( W$ b' H0 N
- {
. x$ h" c1 A2 f! q - //消息转发异常处理,本次消息忽略 继续监听接下来的消息6 U- o* x1 J8 ~; k" g$ L9 f/ {/ _
- }
, G/ ^$ l; p! I& a& W* W& p - #endregion, O) a( m3 y+ K s p* l
- }
6 m/ I0 y( i& v - else
0 e& O% b# }+ [ - {4 I* w. R1 r1 P! Q% y- G0 D4 `
- break;
# E# r; R! q; S2 ]. Z - }0 |, t' }: C* K% n/ J$ `
- }//while end. P0 u5 U8 q7 t+ o! a/ r* W4 V9 m
- }
1 K$ w' R/ K& I3 l5 p - catch (Exception ex)
, A; |, r* q1 p& n+ r - {
0 O5 \' u$ |5 Z3 k6 @. y6 a - //整体异常处理
8 }& F2 l3 c0 c4 i2 _8 q - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
' L9 [3 o$ r, @: U* p) m- D - }
7 @/ m( N: m" |( S# j - }" t7 D- J6 t3 o" T" V0 |/ H* p
1 Z0 S0 D) _/ p7 ^, F+ R! Y( d- + P! d, M" z1 f
- public bool IsReusable
/ I; b! Q7 o# q/ w - {
$ g- q/ w/ e1 v - get
) t! G! T/ J" j ` - {2 |6 o# {6 f \. |* z! a9 o
- return false;. k+ A" |5 H( }5 h- K
- }) h8 ]8 o2 q I; Y# v1 M- b
- }! e0 [9 ^+ e7 b1 ^/ T% \
- }$ ~3 q, m" t& }4 J$ C c
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 6 a0 F8 C6 Y$ T3 l5 x8 [/ h
|