|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
8 W" q2 r$ y# Z8 z2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
- V' g) @+ K# }( S, G - using System.Collections.Generic;
6 `/ V: f: c* r ? - using System.Linq;' o2 @+ W$ W3 f" L
- using System.Net.WebSockets;3 }4 o+ N4 \) |0 Q/ h6 w, L$ ?
- using System.Text;
( ?8 {# |6 H$ w% F8 S - using System.Threading;0 Z3 s( J4 g6 @5 y; F' V& a6 N
- using System.Threading.Tasks;8 V& S9 L' ^. Z& W4 T+ Z) I; T D& H
- using System.Web;
( {0 R" c0 F: O4 X7 Y7 W" v, h - using System.Web.WebSockets;) A5 R5 Q9 R" _6 u$ u, {
$ p5 l+ o p2 A, a/ N9 X z- 8 e h5 s3 @8 P' h2 s
- namespace WebApplicationWebsocketHandler# {5 }; N8 Y+ t3 g5 \( O
- {
' a6 }& T2 Q/ X. V) G) k - /// <summary>' Q( s7 b& E' s B- l
- /// 离线消息
4 s( z+ n2 u6 Z) U/ {* d - /// </summary>/ {& J* K! m! c9 ^3 A0 k" k
- public class MessageInfo
! Z! y; q1 P. n( h4 E& c2 v - {2 F$ {: c% R( z; k3 f6 X/ ^
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)& n1 p, o9 n4 {
- {
: d) B4 j0 C/ p7 R. z* \" B - MsgTime = _MsgTime;
4 z4 ]% S5 V, U7 Q2 ~8 d/ v- [6 p - MsgContent = _MsgContent;; F1 I5 E# U' v- ^; x
- }
$ |9 p' ` x+ t, m' P) N/ N - public DateTime MsgTime { get; set; }% [( r3 h4 g/ M- \+ v
- public ArraySegment<byte> MsgContent { get; set; }& A+ @; L9 i- M
- }5 K& G, ^* o* [' ^0 J% w
# k- K2 X% v# D* E. g5 A+ @- , Q$ l* p F- P% `) x8 ^
- : ~+ f$ R W4 a. s
- ) V0 e7 A+ r9 u5 |' P( o n
- /// <summary>4 P! j% h( n) {
- /// Handler1 的摘要说明
5 H2 `9 V# | D" j" N }5 A4 [ - /// </summary>
1 c$ V4 q) _% d9 e6 K( `% S - public class Handler1 : IHttpHandler$ R9 F* y( z- M! [6 X+ V; {
- {4 M% i! \0 D0 ], A0 Z! X7 n
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池2 w( U7 u/ f- J! Z; V9 c
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
4 B7 K& N8 Y8 r+ D3 _( { - public void ProcessRequest(HttpContext context)' j( X& S) T: O& M( P
- {9 q m, o; u8 D# i; `
- //context.Response.ContentType = "text/plain";
) E0 [7 D! ?( j - //context.Response.Write("Hello World");
$ ?7 y% W a# J; v/ `# h6 c - if (context.IsWebSocketRequest)8 O# C2 o% M* a0 N6 I! D, U3 d
- {& ?$ x) v$ V2 y8 K6 w" Y4 T
- context.AcceptWebSocketRequest(ProcessChat);2 J0 Q. B7 G9 }- E: y, M0 Y
- } 8 G0 ]2 K1 F$ A n, G0 J$ [
- }( E7 H! W; I5 L7 n# Y9 z
- , E7 b& m7 u* h( Q
- private async Task ProcessChat(AspNetWebSocketContext context)
- O" S/ z' B4 b - {
# J" p' y" s5 `+ w3 W: v8 Q( p - WebSocket socket = context.WebSocket;
; N- _$ r! M- \; A- G2 m - string user = context.QueryString["user"].ToString();
3 M. x4 U( ~) o5 q - 2 V& }; V, e l
- try
: Q# l& x7 V' l6 ?. Y; c% U7 Y" s - {
' J0 I2 W) q9 h" W - #region 用户添加连接池
9 H2 K- {; k' U0 y, m. C - //第一次open时,添加到连接池中
; a/ r: R3 v7 V# v$ P w - if (!CONNECT_POOL.ContainsKey(user))% E' U8 s; |0 H6 ]
- CONNECT_POOL.Add(user, socket);//不存在,添加
' X) j: \* ^- W; ~0 Q t - else" j7 C8 q' ~! [ _7 o2 v3 z
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新& V; x3 c! X9 [8 V( ^3 [
- CONNECT_POOL[user] = socket;- F7 }; [0 |5 m
- #endregion
7 `4 q5 W' g8 G - 6 t) ^% o; G5 _3 C, A( V
- #region 离线消息处理
- P+ o2 I9 U8 _& t' m) A - if (MESSAGE_POOL.ContainsKey(user))/ Z2 {. D% w: x. Z. i
- {
5 i. v! J, P9 e6 D - List<MessageInfo> msgs = MESSAGE_POOL[user];
% V# {& G, v8 \9 ?0 l3 e8 }, r - foreach (MessageInfo item in msgs)
6 u* J( y0 l2 s- J0 e- Y* ]( n" p7 [1 V - {) ]* Y, t0 `2 d5 w! _# X8 g
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);4 D( m8 J* _9 }; n6 H% Q r
- }; i7 r8 b Q! g5 J1 ^0 j8 b, H
- MESSAGE_POOL.Remove(user);//移除离线消息
. e: {4 @3 V4 B6 { - }
0 S$ t4 j: a) A5 r2 @8 B- G - #endregion8 ]9 `- j% L- f
- + ^! @: P U: i; S
- string descUser = string.Empty;//目的用户 D+ w4 K. q7 J! w K6 ^; |- J; ^
- while (true)3 j' i( Q0 @) P! P( ~- d& O
- {
3 T' b7 u0 ?$ i* Q - if (socket.State == WebSocketState.Open)1 ~6 a- l6 M# a, j! i$ u+ J3 X1 f
- {
8 E* d1 Q4 V* A# ?2 [; _& @ - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);# K0 f/ L* ~5 M0 H. E4 e
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);3 o x- K8 h. t* H; f
- " D+ R- v7 a) u
- #region 消息处理(字符截取、消息转发)
8 F) B( K n b9 `' S$ N( n - try7 W3 n) ?7 t2 C; t+ x
- {% y5 v3 N1 d# e! A6 Y
- #region 关闭Socket处理,删除连接池3 Y8 O; q4 Q: X; J7 A( K, U* S! E; [
- if (socket.State != WebSocketState.Open)//连接关闭
% z i. b$ A6 j3 o1 z - {
6 K/ g% U3 f; p$ G: k1 \ - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池5 @0 _1 }1 N8 T$ ?2 \
- break;5 ~& S9 ^/ `3 [7 ]
- }
0 G+ R; J |; \7 Z# D1 c) p - #endregion- x5 e- Q) B2 J6 s" G
3 h* n$ d0 _, g6 b- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息$ t( c% t) ]. y6 D8 S! t7 c' g; x
- string[] msgList = userMsg.Split('|');
. q; Z; c% R6 L% K& j" b% q' @* E - if (msgList.Length == 2)) K5 I. @, H& A. }2 T0 T
- {! r. n' ^# _3 H) N
- if (msgList[0].Trim().Length > 0)
1 u) g7 z( w+ @/ n4 a - descUser = msgList[0].Trim();//记录消息目的用户
' g3 w o r3 C/ p3 o - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));9 u2 j' J* S$ T/ p8 A4 l9 t
- }
5 p; K) T0 M) Q6 p - else
6 w- P) L* d z8 b8 l - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));, r. ]+ K" ~4 L% T
6 q; H2 J4 P+ C2 M9 U- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
" p* c. x3 {3 d! Y - {2 h" v2 a9 E+ l& S
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端' q) S3 i- Y( c& @! `5 O
- if (destSocket != null && destSocket.State == WebSocketState.Open)
2 D+ E% R6 ~' [1 ]$ v; h - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
! z9 n2 Z: j8 o7 l3 W2 T0 T% o - }- c6 V3 p5 T3 h
- else' o7 Q( ~# T& d/ l
- {+ g1 L6 U2 t* B
- Task.Run(() =>
) ~* T C I/ }7 d% b8 b& _ - {4 O1 q2 t, r& H' m* U% R
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中 z- A4 x. ^0 M" T
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
3 f+ N" i# d$ r$ ?5 Z9 U# U - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息' {& d6 x6 f( q# l$ E3 t8 }
- });' _/ J' s- y# I. p- L7 U
- }
4 I. H! f4 H4 n& u* H' ~% L# J - }
# ~8 k4 v) s* D1 P! y - catch (Exception exs); O# e0 p+ _6 S4 {7 x0 B0 F9 @
- {
, i0 J4 i+ d) [) J$ R& A- y - //消息转发异常处理,本次消息忽略 继续监听接下来的消息3 U( z' C7 I5 `9 [& c8 I+ n
- }
: k6 B1 o5 m& W+ A/ H: g* J - #endregion+ t+ T8 \& I1 I. s7 i
- }
' L2 w% R6 d5 c5 b9 A - else
* u' @" b3 {9 d - {
* P$ l l# W, H: O' |, T - break;
& M. Q1 ^1 g7 ]" \+ j Y: l( V2 r - }
4 q, ~5 G. q% @1 t# {4 Z+ x - }//while end/ p9 @1 Q3 ?5 H( T
- }
0 o J9 |5 Z; s - catch (Exception ex)
! E6 q# n+ k a( C2 u( P - {
7 `1 r0 c! |9 t. H& W5 U) y. N - //整体异常处理) B% p( G% {! v- t
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
7 w8 j5 P0 m* E Z8 s6 A - }
4 |9 `* x$ D: M - }
1 _% O B5 I( X; b: L$ T - 7 G$ Y t: V$ l
- 7 \2 ^3 h* C, K X- P* j
- public bool IsReusable
" L/ B* L' a! m - {
' n% Y! \5 F& \3 l2 ~: P# } - get/ N8 }% y% ]8 R# J; _4 N1 P! [7 y' F
- {# \0 U' D5 I; g5 N3 e
- return false;
# q3 Z/ M4 b3 p' z5 L - }
1 _8 s! D0 ^2 E8 a8 J4 x - }
* @; |4 J0 t* a( C - }
3 R2 ? v8 Z! W* f/ a - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
9 N. ]2 ^: P8 P |