|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
3 k* \0 m- p9 P+ M2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
9 Q% q, v) k) f6 B# K - using System.Collections.Generic;5 [( H: b9 c& U- l6 {% e& b
- using System.Linq;
6 g* `1 \. k" r& X9 M; u, e; O - using System.Net.WebSockets;
. K7 N6 F$ O P6 X) m4 L* b - using System.Text;
# N# G- e9 U& {/ C) Q - using System.Threading;
1 B, J" ]& `7 G' t - using System.Threading.Tasks;
9 |( G/ ^) r4 j0 S' ]5 X: ~$ G/ p$ ~ - using System.Web;) d- y( R# G! H( B$ V
- using System.Web.WebSockets;
0 Q& w# S( e* o. ?
! v0 ]( H; E. f& M
, [8 `# |4 `" j, A8 ?$ D- namespace WebApplicationWebsocketHandler. Y. h8 s/ {- V7 R) {6 `- j
- {$ ~2 {& Q, L' U( R4 \
- /// <summary>2 x1 M( o. P) e9 D
- /// 离线消息- S1 D7 G- b$ l( ?
- /// </summary>
N* N8 v: p+ }6 |4 Y$ e/ v2 [$ i - public class MessageInfo0 _$ ?2 N$ {- _( L# e; n. y/ E4 M7 w( I
- {
* J& x$ y/ c. n# x3 |$ l }/ D - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)' F% ?8 Q/ P& q5 ?" D! ]" x
- {
( ^8 h$ d/ `( s( b0 h - MsgTime = _MsgTime;6 A6 j) S7 l; K0 V4 b n
- MsgContent = _MsgContent;
) K' }; R8 K3 ] - }) Y+ i U6 i4 S W4 d ?$ n
- public DateTime MsgTime { get; set; }9 `& d! C. {* R
- public ArraySegment<byte> MsgContent { get; set; }7 _, Z9 O6 q, p2 e+ v9 U( y
- }
$ H# U1 p" @ [# r! a - ' h7 m, k+ m; }( \
- W' f+ w+ ]3 q* a
) g& r9 A9 A. Q* j
' L2 h0 L: ~' M9 F9 C3 T& l$ t+ q- /// <summary>3 Y% c& [$ H2 @% c" n
- /// Handler1 的摘要说明
" m: i) T3 D- K& F) N: x# m - /// </summary>
4 k( U/ |- }8 { - public class Handler1 : IHttpHandler* t3 |2 E6 x1 F: `' @
- {
) x" }- p; Q6 k- Y5 B% Q& g, ? - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池" s" ~; B# H2 [6 P! X' x
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池; ]( R) g7 j% I2 M* v3 r$ E0 W% j
- public void ProcessRequest(HttpContext context)
( t1 s3 L" V1 v m - {
- l, X! y0 _. _% Y. D$ w# ] - //context.Response.ContentType = "text/plain";
% @7 Y. f' \* W+ M% M8 U - //context.Response.Write("Hello World");
' M: F) v+ S* y3 U F: h - if (context.IsWebSocketRequest)% B* u! `, E) A6 g
- {! \; a' r# x! ^$ I, |) g3 L. U
- context.AcceptWebSocketRequest(ProcessChat);
& A! P/ m. j+ L8 R - } 3 x/ S, N9 m I. n# o: H
- }
" t. `1 {1 O$ Y0 F
) j1 e( H# O& W# H- private async Task ProcessChat(AspNetWebSocketContext context)
* J5 J( s- `1 F# ]! p$ ~9 j! @7 G - {
- @1 |$ a X$ Y: I8 ~* | - WebSocket socket = context.WebSocket;
9 G" l3 \9 o0 `/ W0 n; Z - string user = context.QueryString["user"].ToString();& M" t, S! k' X
- 1 |" L/ Y, B! Y1 W) q
- try/ l& h0 w7 n7 [& e& s2 x* ]
- {: q* s4 i! M0 Q+ p0 m
- #region 用户添加连接池/ `9 } e8 K2 q4 @3 B, O9 I5 c* ^
- //第一次open时,添加到连接池中
& U6 Q2 y. u: V% @& b - if (!CONNECT_POOL.ContainsKey(user))
6 x" F' A& N% E - CONNECT_POOL.Add(user, socket);//不存在,添加
1 G! }4 I7 d; m - else
6 e: E4 B# F* K - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
8 z4 `9 U) d" K4 } - CONNECT_POOL[user] = socket;0 y, ^& b/ m2 {
- #endregion3 U6 A; k4 d3 h4 K
- ' d. D+ v8 o6 }) f& l
- #region 离线消息处理
. `' T5 h+ B) J0 I4 i, P6 C - if (MESSAGE_POOL.ContainsKey(user))
2 [3 O$ `1 X+ o$ K4 O5 y) }' r - {' K/ a' ^# w I: \! g9 B; N$ U" {
- List<MessageInfo> msgs = MESSAGE_POOL[user];
& L# J M3 { e - foreach (MessageInfo item in msgs)) ~9 }& K- @& f3 u$ H1 ^
- {1 P% Y+ l: H* }0 r. i# C: R
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);* ~! p, I9 R% x: Y! Q
- }
% M. p6 \$ j/ A/ T - MESSAGE_POOL.Remove(user);//移除离线消息
! w" S/ |9 [' B6 m+ ?; W( } - }% n; k' d5 C+ }4 q
- #endregion2 v1 q2 m# Z" _/ ]6 D
& k: a u3 X& H( @7 U7 V- string descUser = string.Empty;//目的用户
* z0 ]; m6 n) k( X4 p) ~# [+ Z0 G - while (true)8 R$ W/ u) u U$ m
- {
, [3 `/ E) o5 a* m: R' Z4 d) a - if (socket.State == WebSocketState.Open)
, u v7 S+ Z8 V0 @% p4 E% C U - {
3 M$ Q! h b+ J7 `# n7 ~ - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
" k, Q8 y, p! Z! \ - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
2 I% G0 {" Y. c! i; W! T( a1 X9 X - + T! c7 K D Z+ ?6 ^# j
- #region 消息处理(字符截取、消息转发)6 V9 v5 P* T l
- try4 |' y! K0 n4 z" g
- {5 H" |% t$ v& L: ?
- #region 关闭Socket处理,删除连接池
6 j- h q6 | } _7 {0 h8 A - if (socket.State != WebSocketState.Open)//连接关闭
: b9 C W, u$ O9 Y& A - {2 D3 b3 C& G& S# h# |
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池' @! I/ H; p! s5 \( f/ A5 T
- break;0 Q0 U6 \+ f( G) A) c
- }6 a, g( c& h R2 b( i1 j
- #endregion H! {+ U8 Y/ {; [' J- h$ L+ J
- # H: c" w$ q9 u& h7 a' ~/ O/ \( j
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
, m! j! k" m9 V' h- M& W! O P - string[] msgList = userMsg.Split('|');
- [0 r2 n' Z/ v, O% O( s - if (msgList.Length == 2)
# W+ O5 A5 t% `* ~- ? - {/ C, b0 M1 O9 R
- if (msgList[0].Trim().Length > 0)- G- ^6 b6 }& P i9 c( R" C# J
- descUser = msgList[0].Trim();//记录消息目的用户/ J" W2 t' K/ F
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
6 {; n5 R4 a; i+ U6 m. U( P - }
* s% W* _8 @5 U P! z - else0 m& d5 y4 a) L9 c$ u& A
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));" H: t" { T J5 B% v9 ?* f
: x* M% Q/ M/ c; T' x- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线5 x: z+ U5 S5 [
- {$ t+ `8 B. u/ e
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端7 U( ~7 C) P$ ~- r9 q( Z2 ^
- if (destSocket != null && destSocket.State == WebSocketState.Open)5 l9 D; V3 G2 S: |- r: O% B9 g1 U
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);8 M5 ~! W5 t2 G" O3 a
- }" c. G! M4 q6 Y( T( C1 u+ y
- else
: f: J3 s0 Q: r! c - {5 h# l. C( m9 X( s
- Task.Run(() =>; `: K! N2 u) p( A
- {0 E. i' }# |: o
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中% h t% g- Y9 P% n) j$ u
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());$ `$ q5 c+ Y8 _ G3 Q; M% D5 r. f
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息" }8 r- g: S- K4 q+ U
- });" ^0 p6 X8 r' t, ~: m5 H, c* S
- }7 r* ~% C5 G5 Z" F6 Z
- }
0 [* I7 }: L8 U# W+ l" M7 s0 R5 h - catch (Exception exs)
6 t- v7 {' [6 k8 ^, m - {" d1 U3 E+ ~/ J7 j0 o4 }
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
( @3 m1 ?2 U4 _9 g( d - }' i( U, I) v) M. y0 l% p% O$ c/ V6 N
- #endregion: h! G$ ]: n# d. H8 ^
- }8 W0 o. ^! K9 B% ~- |
- else( t) H1 R; [6 { S( h& L( X& L0 i
- {
$ H4 M7 o2 t6 e - break;" L* I7 X; b4 C. a1 X
- }, d6 ~8 P* W# J' s. |* E
- }//while end. H0 w" b9 L- M2 M; Y( t
- }5 e; h& S' b( c3 Y$ ` `
- catch (Exception ex)
" ~2 K- y" P( u3 G9 w - {
5 w1 h! t3 }& \% g M# G - //整体异常处理
9 z& V: Q) f8 N; y5 s: M2 R9 a8 u - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
. W- U. s! {6 Y1 Y; I - }; X% ?8 h8 | D3 A n% N
- }, u# {1 [2 E9 X: J# B& A5 D
9 ?' C" C2 v1 }. ?$ C# D
6 B% A1 {, A1 c- public bool IsReusable6 Q7 y9 ` e* l; D" C+ |# f
- {4 L7 b7 r; g. p+ o
- get
/ {8 o. d& M0 }$ P) k, N3 l; l - {
3 i. y. ^& \! u0 A. y; c - return false;
% x4 U1 H$ T; W; M% D% K - }& ~9 W s7 \- H1 B4 Z* H
- }3 s: r1 F0 e. r+ K# Y
- }
) n: ~5 Z; o1 P$ ?* O$ O9 N1 A - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
3 w% G4 X( Q/ T j |