|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
; o" S0 L" R" V- F* Y: y; d2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
( q ~- C8 J- ? - using System.Collections.Generic;$ v6 B; ], T* `- q
- using System.Linq;
, m7 t5 R4 J* d - using System.Net.WebSockets;) @/ K+ E. B" n; v& O5 x9 f
- using System.Text;
' m6 d2 U+ G6 g; ~7 v, t - using System.Threading;- X, Z7 v7 [$ g* }1 L* x0 a
- using System.Threading.Tasks;
) b0 Q$ H2 v/ x' b' [7 R* p - using System.Web;
% k! A( g( ?( o: x - using System.Web.WebSockets;4 f- @" x% g/ ^3 `
- - l8 W/ d# y; V% ` p2 W7 e& @! ~
8 \0 X6 p1 X, {+ M+ k- namespace WebApplicationWebsocketHandler, P# w& W% Y$ J- x& P5 F( R+ e# _
- {
2 T2 r* f- u" C; x - /// <summary>: U/ d4 o4 s: [ r& G
- /// 离线消息
! Q1 t, W ?) R+ G$ n - /// </summary>
8 P- D+ q) z; w2 a1 j2 c1 g7 c( \% z - public class MessageInfo
& Q3 V( D* f/ q" @$ k4 @* I7 Q - {
) Y) Q3 W( h; s - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
3 P( p4 V: [% G3 f& U - {
9 P9 G) T* p6 Q2 C2 X - MsgTime = _MsgTime;( F5 u: }* t0 T. ?; s. S5 P W2 Z$ b
- MsgContent = _MsgContent;+ l+ S) ^' K a7 J8 `
- }/ Y+ w5 ]; H, D2 W' i
- public DateTime MsgTime { get; set; }
' |) [/ Q5 o% I+ J - public ArraySegment<byte> MsgContent { get; set; }- v8 a& J+ d7 q% t1 D
- }
: \: _2 t/ g2 k* n( T7 c
: V9 a j5 k* }5 R' g" O6 N: b
* K( `1 U) }) B" O% O; v
& R) I& V% f. K; ]6 _! N' ^
" x, ~& L+ }# R f! p* T! Z( I- /// <summary>" s g; s$ R/ X8 r ?3 a7 ~
- /// Handler1 的摘要说明3 j% s* A' Y5 w1 n4 L/ J( D0 n+ h: o7 f
- /// </summary>
* N) L" b7 l1 v) ^8 ]. }) N - public class Handler1 : IHttpHandler
7 f. z; Q, k7 ?! [$ G# J" Q' g - {
' h) O1 a, \- A& ~, l& G! M - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池# O; v. Q0 p1 ~. O
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池8 m t3 Q P5 a- P+ t& t$ Q
- public void ProcessRequest(HttpContext context)- {: n# p" e1 o) n
- {
/ ?% k1 A8 A: i# H2 D4 V! P& s9 K - //context.Response.ContentType = "text/plain";
9 H, w" `1 O4 m! ?0 v) n7 U - //context.Response.Write("Hello World");! T4 a. L: {$ h9 o! j
- if (context.IsWebSocketRequest)0 B# @( |" k9 ]* D+ t" ]
- {) d4 M% {+ A3 w3 }
- context.AcceptWebSocketRequest(ProcessChat);: x& V. N- w8 C1 D8 b
- } / o$ Z7 s6 h/ t/ U
- }# f' O! D& x! B; d! m0 h, b
/ Q1 L( J$ b9 l9 W9 F) V4 e- private async Task ProcessChat(AspNetWebSocketContext context)" e5 g; E( P+ U! ~# [3 c# n
- {: q m7 c$ O; @5 u+ q) @/ k$ P' m
- WebSocket socket = context.WebSocket;
5 H/ X$ U, f; G: a: J/ b; p - string user = context.QueryString["user"].ToString();8 j+ T+ W2 G3 U
5 E) f, K0 X7 P- Q8 {6 m3 G- try
) Y$ C4 a1 W6 R - {
P1 p) ]- K- a2 ?, w& m: u+ t! D ~ - #region 用户添加连接池
) i$ k; M$ x( _8 i, G3 B, E - //第一次open时,添加到连接池中
5 o' X' R0 \6 Q: G7 a- ? - if (!CONNECT_POOL.ContainsKey(user))1 L9 j2 a) L- N, m# t
- CONNECT_POOL.Add(user, socket);//不存在,添加 d8 f( W; X$ L% R! z& D4 V
- else
$ ^: ]' @- p7 ^+ Z/ ]- e - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
7 }! w. i, g7 A - CONNECT_POOL[user] = socket;3 V% \/ i$ ^+ B
- #endregion) e+ q! D, x# [0 e
. x/ q9 Z: F+ J+ ]; M' ^0 w! q- #region 离线消息处理
l/ D' j7 c: N- B3 \ I- c - if (MESSAGE_POOL.ContainsKey(user))
; R9 l* C! S% y4 w - {1 k1 s; d# q$ P' A1 q7 F
- List<MessageInfo> msgs = MESSAGE_POOL[user];0 s7 V3 k2 [. W, e, i; u
- foreach (MessageInfo item in msgs)
! i$ o* p5 _3 l. w8 }+ I - {
+ ?6 A- |$ ?& h* H - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
* D* _7 A& M6 N- { - }5 O" ]# s. ^+ D* I, E! H' d
- MESSAGE_POOL.Remove(user);//移除离线消息9 h) w5 Y* M4 d! _, W$ |
- }( y5 Y2 o. n+ x) d0 H
- #endregion7 F$ t& g0 s' W9 [. ?
- 4 e' x' _! a# Y% v; t
- string descUser = string.Empty;//目的用户
) u; N# W: |( U& B8 A$ k$ z9 R8 A. @ - while (true)* T" y$ Y$ A) G! z( o( o3 S9 [6 {. q
- {* }9 @9 Y8 q4 O5 b: C) B4 _
- if (socket.State == WebSocketState.Open)
2 Y" c% a6 h! z3 B" v - {
5 s0 |% ~7 P$ L - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);/ m: V3 R4 B& h5 P+ h1 s
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);2 R* ^5 N) y* A# i2 I( B9 G' H
8 v# X4 H: f6 H( Q0 `; c+ y- #region 消息处理(字符截取、消息转发)+ R+ i+ Z z" E' ^+ L' Y
- try
/ Y! i* ` t6 B* a3 m* m - {
p( b5 T- x* C, A" p! J; S8 E - #region 关闭Socket处理,删除连接池
4 r6 J& M+ a1 V6 ]$ _7 S Y - if (socket.State != WebSocketState.Open)//连接关闭
) ~ [% L( E/ Y$ V - {
% R, }' [' _. M/ E1 m( r - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
' W% b# U! v7 ?$ X( k7 N0 H! U x - break;
4 J; w: H8 v4 B( l8 } - }
1 g1 b4 c9 n# [! p - #endregion
( R- i `/ f- r
8 j" I8 k9 v3 p0 \+ W- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
& r' P# C* e- m+ r. ?' G: c( O- D - string[] msgList = userMsg.Split('|');+ }* y" K6 J# R. u) R1 o4 W
- if (msgList.Length == 2)
2 w- }4 E/ e' t5 V- ~ - {
7 u+ j: @( Q, ^ - if (msgList[0].Trim().Length > 0)
9 s4 I& r/ x* r8 _; a6 ]+ H - descUser = msgList[0].Trim();//记录消息目的用户
! x' y0 v* f4 s, q8 L7 a - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
( Z1 m0 r. N( x$ h) e - }
- B& e/ {! O; t - else' M+ @! W4 M9 U x
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
' [( Z' o( p. m% m
$ G6 s/ Q* ?3 i5 a* C4 s- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
" ?7 C6 w/ r! [- f - {
: n7 q L/ P; B, p# D - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
; C; R, J9 Z4 w - if (destSocket != null && destSocket.State == WebSocketState.Open)' `* `% l' Y3 j' f& T6 p8 K- a1 b
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
+ G$ K x% v' e# }+ ^ @ - }
1 w' d' y9 w# W. R/ |" p& G0 @- O - else3 {# x0 u4 h: ~: C& i8 t
- {9 u% J% H+ ]' y- ]1 O
- Task.Run(() =>
5 [" b' q* c& `% N( ~/ b - {: m: P: _' o5 H, [' ^: y% ?7 A2 w
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
8 u, ?! l( n1 y' {8 U; Q - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());$ N- i* k! u4 Z/ ]5 h# Z
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
$ J; K- ?- `7 q5 @/ a: { - });
, Y1 m! S2 {! S* a - }
% Y) d, S4 y& \% y: C' f - }
5 j8 s, ?7 \' j, J# _' e0 a# H - catch (Exception exs)
7 I! i. a, }. V$ n: c - {, B2 t, v0 n x7 A
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
# |; F% s$ x- N - }
, ^' C! u8 m( d& g; K& T+ u - #endregion
7 \/ ^, ], w) G$ D/ C# z* s d - }. k8 G6 G: @, T
- else' x$ f2 h9 Z- T! x
- {! H' W0 V& h, }. F3 g" _/ u
- break;2 F# t2 ?4 S- b
- }1 d; J+ C( `7 u2 p: l, ^6 q8 P
- }//while end
& q( _4 ` s4 J6 g/ k _7 K' J: A - }
2 r U! R g" S. M* p2 z* F - catch (Exception ex)
( Z, V3 Y& Q4 b/ ]6 q2 T - {
% k) z* W4 `3 R5 ]5 s- p, u - //整体异常处理
% e$ Z9 r( k# L5 _ - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user); I2 q4 N& ]- n& Q
- }
4 P( N" M. Q& s+ J& |9 Y0 h' s' e - } v% J# @* c7 h* [. I2 W
9 `* P2 ?- G2 p E5 H
( i2 I. _0 g: L1 t4 x* h- public bool IsReusable) k* Z E/ M3 o: Z: g! m; q u
- {2 m. o/ y1 ^: r7 L+ w; Z
- get7 |* V7 h6 H+ O. r9 c9 s1 _. o
- {
* H8 _" T& o/ [. d' K* l - return false;, Y! R8 b- X' g
- }
/ n7 ~8 R L6 K% t6 s - }" p, o( {' v% I- C- k# G1 K2 y) r9 r Y- |- ]
- }% B" \- \1 Q- F2 N
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 7 H) e: L0 w$ W- {. J; B- u7 E
|