|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 9 R H- a" k3 ^1 L* D% p+ n
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
% L% k: x9 d( @ - using System.Collections.Generic;& F+ C. i$ h6 w4 b
- using System.Linq;# k0 y c4 y7 \! V
- using System.Net.WebSockets;
5 P* y( Y/ X4 Q( c/ i, R - using System.Text;* _* l/ U7 \9 D& c$ L! l% S' x
- using System.Threading;
* g' z3 c7 t1 N: h- K - using System.Threading.Tasks;: F$ E1 i! f! g1 ?- O% Q
- using System.Web;3 l, w. j- v* f% O( H o7 L
- using System.Web.WebSockets;1 V! I* F/ E6 m7 U& O$ F
- - k% h+ m: J5 _; t1 A
- 8 l8 K! {- S( t" f
- namespace WebApplicationWebsocketHandler" ]8 Z+ G% p$ {
- {: R% {) L1 e, ~; _
- /// <summary>
6 y0 c: ~3 |: Q8 e7 Y& B - /// 离线消息
: x8 P, c, d4 d- J N* z* l* Z - /// </summary>" c$ q( k z6 ?3 P. J2 x
- public class MessageInfo- p2 G% g5 X( M F% s
- {7 i) _5 b9 Y5 F+ z1 y6 b+ o! E/ |
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)$ d4 f! Y. O$ N4 U% `4 B
- {
4 |- L2 m: g" c2 \ - MsgTime = _MsgTime;
& P3 X8 \) M p! W; v2 K - MsgContent = _MsgContent;
4 t! z; W" N2 {" Z* V$ l - }6 k3 p4 N9 D2 I) N
- public DateTime MsgTime { get; set; }
' H5 R/ t4 |. K* ?7 A( f - public ArraySegment<byte> MsgContent { get; set; }# _* D) |* X( S! m; K. I+ m+ `3 y( x
- }5 x; B* L t; u g- a6 U
/ |: S$ a$ p5 [. H8 l8 |6 n; V7 v5 l
/ N9 X! n" r* l7 Y% s
( }/ ~# m% C; e* F6 E# G! f- 9 V( s R5 i% n
- /// <summary>
8 u) I# ]" H. F& j" N9 O - /// Handler1 的摘要说明
5 I3 B3 @" Y4 C( I x9 c - /// </summary>4 T' u- O! C* i
- public class Handler1 : IHttpHandler
1 c7 n* j2 I* V/ f% m: t, c - {
' {& } s# p7 f1 ~; p) F - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池0 l# t- B' _! `
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
2 C& n5 f1 L, Z4 n - public void ProcessRequest(HttpContext context)
5 T; o: i1 S4 s- B9 h - {. {6 o& T( |% k" w" k* V8 [
- //context.Response.ContentType = "text/plain";
- ~0 Z& J5 r+ X+ @& O - //context.Response.Write("Hello World");* w* ^5 ]7 S' [7 r1 \
- if (context.IsWebSocketRequest)6 D9 a. L# [- Y1 f" E* C
- {0 e4 P! W" }: @! S. `: c" z
- context.AcceptWebSocketRequest(ProcessChat);
: G. _7 b+ b. i; X; I5 v+ d - } ! O" v6 c" P6 E" T9 d
- }
# a4 K/ {& p1 J9 L5 s - . l! @; u M7 H, O/ [3 K, D
- private async Task ProcessChat(AspNetWebSocketContext context)
# y3 G" U) H; F, {" o9 Q* T5 d - {
8 o1 M% ^% B, g' C. B% a - WebSocket socket = context.WebSocket;
! S" I/ q1 A7 S% j - string user = context.QueryString["user"].ToString();; ~ S! h) H9 }5 L' Z% U
2 z& e& s* \7 w4 e- try0 o, o7 }% x8 B
- {
7 D1 B$ n* X4 E1 {2 ]4 E, ?4 r$ z - #region 用户添加连接池
/ O% q+ q6 Y) L+ j( D+ M - //第一次open时,添加到连接池中( D$ j* \$ `" _0 a, V
- if (!CONNECT_POOL.ContainsKey(user))
: p! V4 `! a& U* h' d1 r+ r" W+ I - CONNECT_POOL.Add(user, socket);//不存在,添加
2 B3 \1 ]7 P( z4 ?$ [, I - else
2 n; Q9 {4 Z: ]4 k2 w3 K& ~ - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
9 K( D7 E7 Q5 a9 Z" ^# }. C - CONNECT_POOL[user] = socket;
' G6 C9 Z5 P$ N- F& N - #endregion/ g. C$ g7 c% d/ O* a/ X5 @
- : U: c' q9 B- M
- #region 离线消息处理
, s% M9 x/ f4 k, a0 f/ @7 U - if (MESSAGE_POOL.ContainsKey(user))
2 D6 d# E2 A4 N5 b - {& u M5 E( h( S* e9 j8 h
- List<MessageInfo> msgs = MESSAGE_POOL[user];- b6 f, Q4 X, b& M! v3 t! Y! t
- foreach (MessageInfo item in msgs)( E& ^3 \7 E5 s+ N2 S0 D @) @, U
- {* g4 `- x$ u; \: h3 C# ` m' E6 Q, e
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);% Y: f& n! B" g) t9 B
- }
, S l3 `' t+ _ - MESSAGE_POOL.Remove(user);//移除离线消息
: b: i! D8 @: V- S4 S - }
" w, r# i# t4 @/ ~4 j - #endregion
/ R8 J+ V: v6 q. }! X v
! ^* ^$ V$ f. e) D# {: `- string descUser = string.Empty;//目的用户
( d3 y9 z- d: }$ f" l/ ?! v - while (true)5 e. F6 _0 S5 u# N, V2 q+ v7 m5 X
- { G( _ C- |1 U2 S- I0 _& x
- if (socket.State == WebSocketState.Open)
7 K0 [: u" r8 s - {# p* V( J: B* I1 ~6 ~
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);: s8 `5 ~1 b9 Q% O( w
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
{5 X* |# [1 j - 4 D! h ]- z+ x' d. i
- #region 消息处理(字符截取、消息转发)
1 B3 w7 ?- i7 e - try
- a; e9 W5 c# u! L: H - {7 {+ r: V9 E8 \; [' W0 ]! S
- #region 关闭Socket处理,删除连接池% H7 I, |) s( q* n
- if (socket.State != WebSocketState.Open)//连接关闭
8 n/ V3 p H: _. K3 J/ c# t - {+ E/ \6 D4 L- s. I/ s+ s
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
# T! P. ?3 c1 r+ V( f2 w - break;
1 w. ]( B1 e/ E( n) p( j - }
+ r& }; i. o. @; m" N - #endregion" n- }, k2 U" k2 w
2 E! S+ q o9 ?" t5 _& C5 N- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
! `8 o$ T \; b7 l' S1 ]& j* y U - string[] msgList = userMsg.Split('|');6 l% h9 h. y; m* L
- if (msgList.Length == 2)
# f; u9 `3 V5 q" ~ - {
M5 j, _6 G' w5 _* O p - if (msgList[0].Trim().Length > 0)# g& J# W6 F) \' E: a/ i
- descUser = msgList[0].Trim();//记录消息目的用户
5 h+ T# G' h% i' m2 h/ f9 h e - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
: v3 o2 T, h" V* q; ~4 ?4 a - }
$ |7 q$ _# F6 W$ D U - else
+ u O/ [( z+ N+ M" x - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
2 U4 y' a% z" W8 {% t
' U; S L* I) h( d! S6 ^; C' N- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线, x6 W% e9 l5 Z& T0 T5 e% f
- {1 f3 Y r6 T$ e+ b' Z
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
; t& n% V2 E% C3 X0 t - if (destSocket != null && destSocket.State == WebSocketState.Open)
) r; ?+ @, S5 b( S5 Z2 ^$ y - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
6 l! Y- ~9 Y9 a$ N1 }5 }6 i - }
7 `1 b' x7 {7 A+ a- e - else
, _6 s" e. _3 K - {! u: R1 J( }; k9 w X' I' N* A
- Task.Run(() =>
# P: k$ B4 X5 ^1 t2 ~6 m; e - {
/ Y2 X; ^* Z+ G8 |; t; i& T - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中* o. S4 t6 v }
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());& X( w3 c ^4 u# g0 ?' S
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
& h6 C( y/ V& z, ? K' i - });
2 A* i' M( z I" k( p/ N - }
+ t" ?( N& t7 X; o, l - }
# R( ?6 }& g0 ^& k0 H* b0 } - catch (Exception exs)0 t P; h4 `2 e" @2 b* L7 ?
- {
& _& |) U/ M& L! x$ u - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
2 S. \: F7 w4 Y. R- H' K' P - }
$ x( q7 Z+ D9 q3 I- x" g( K/ c3 y0 F - #endregion
/ _8 J& i9 ~- A3 A6 i( O - }
4 s# l" X: k, x) s- G - else
* o3 r4 b$ w/ p5 P; k, m( G - {
( u& R {7 X- G4 R+ c" I- n - break;
3 `3 o) [" Z3 s; @/ N - }( e" T6 Y; w+ k
- }//while end
2 d" b( A9 t& p% y. P - }) ^; [; T1 M- \8 Q6 {5 y6 }2 _
- catch (Exception ex)
H/ h/ V7 m0 }3 ?8 w - {" l7 Z) T. [8 p4 _3 S( w9 K
- //整体异常处理
; A$ [. B2 w, u; D" ?+ k0 r - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);. e' N) o2 W9 T& [
- }
$ x. ]7 e( n6 X5 z( N - }
" p8 s% P5 C0 Q/ w$ E
?3 M1 b! D& f1 P: G; \- y1 y* U' e: ~+ E+ S6 Y
- public bool IsReusable
* |. S; t7 j( | - {
. S: |) d- L! X8 O: b/ g8 @7 K1 P$ e - get2 y) B. ?7 ~$ d- K' X7 K( |
- {
! t5 C+ U- O, t+ }* w' S6 k - return false;
) L$ w" M( F' P# i4 j" I ? - }* W) [6 f- i$ d" @6 G6 s) p$ B
- }
' G7 }+ Q# P( s4 W& A* ^ - }/ ^! c+ q# D4 X% r7 z
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
# K6 q8 ~7 C3 {5 g$ g6 |' \ |