|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
& u x1 `; u3 _$ g5 X/ z" s2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;. k5 S3 _- ] D3 [
- using System.Collections.Generic;; J2 r( e) l, H
- using System.Linq;
) C* M. D; Q4 n C3 O - using System.Net.WebSockets;! q1 V; }" ]9 C @, {
- using System.Text;! `1 ?) x, }! w+ [# l& }0 F2 A& b7 X
- using System.Threading;' u7 ]4 Z8 T7 I8 K N8 p# W8 J
- using System.Threading.Tasks;
1 ^. s( K s8 w - using System.Web; p, i3 y5 l# R5 c0 N
- using System.Web.WebSockets;
) w% R, N9 U/ B! d: Q) Z - ! d2 E3 t$ X! E/ O Q: R2 A) t
/ }. B3 Z; o0 K; K- namespace WebApplicationWebsocketHandler
5 ]4 P8 ]1 N" |; s - {8 C8 H; e8 s* L4 ^, k' O) P
- /// <summary>
5 v8 {+ W5 U& n8 D - /// 离线消息8 E" q1 z3 b# |/ |: N
- /// </summary>+ i x; O( C- t' }$ Q: u; E6 W
- public class MessageInfo
9 M& v' t" s8 i" ~" x2 ^ - {
7 @' V# ^! O9 A4 W - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
' C% ]! F: Y$ h Z& M - {
" i# o6 z- f& ]/ @8 J( U' e$ k. ] - MsgTime = _MsgTime;7 w9 O7 d7 Z5 E$ H) |5 u5 o
- MsgContent = _MsgContent;
- h/ Y* L. v! Y( D$ r9 \6 ^) B - }' k8 _1 Q/ O- G# ]# I) {
- public DateTime MsgTime { get; set; }$ t- g. }2 u% u, x; F: Z! C
- public ArraySegment<byte> MsgContent { get; set; }
! j2 v2 m7 k8 N( {; D* N. _ - }( Z+ M' }8 h' u! c8 [' z: R
5 `9 E! }# t8 @& M. C" u, I- 8 g! x+ k% m* c6 G% d/ B; v, a
- ' T) h: d6 x \: W. i
( N( J4 i P+ ]$ @- /// <summary>! b. o7 I& I) ]5 S# U
- /// Handler1 的摘要说明- j: y. M5 A \
- /// </summary>1 Q, ^4 k: [& M8 U9 l
- public class Handler1 : IHttpHandler
% L5 A, _0 B+ w - {( M3 Q+ A( R" n: }, }! L
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池$ ]9 z ~5 T; V P C
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池4 A# C! J3 G4 j" ~4 K9 e, j4 D
- public void ProcessRequest(HttpContext context)9 ~* C8 l& W% q( \' s
- {/ D$ t* V E7 G q! g4 u0 H
- //context.Response.ContentType = "text/plain";
' j7 ?3 M7 g! M# B. T# v - //context.Response.Write("Hello World");
+ w7 y& V; `9 j% b# { - if (context.IsWebSocketRequest)
/ o# b7 p5 d6 j# g+ i5 v3 I - {
$ y: Q7 h; J8 g - context.AcceptWebSocketRequest(ProcessChat);# T5 ~9 j: M4 D/ }) F3 X
- } . F# |: Q$ Y7 F8 Y. h. e) c( [ Q
- }
1 }) i4 w& u# J! Q; S
S% u& y+ [5 Y- private async Task ProcessChat(AspNetWebSocketContext context)
, }) N7 w4 S) V - {
" M: v/ t, d# Y+ _ - WebSocket socket = context.WebSocket;# \5 l# ]+ `0 I
- string user = context.QueryString["user"].ToString();
5 [" \2 V, r& l' p8 j! h; x - % Y1 I- e% m. {5 b: ^
- try
+ T, U8 |: h; g) n" A: o2 g/ c/ ? - {! z$ Z( Q6 a% z7 i
- #region 用户添加连接池$ O: |1 F, z* {; a
- //第一次open时,添加到连接池中
; j7 B% e1 C! Y$ b1 y6 D5 } - if (!CONNECT_POOL.ContainsKey(user))0 _' o, e, W8 [% j8 i$ W$ T; T8 ?+ R
- CONNECT_POOL.Add(user, socket);//不存在,添加6 E" q6 C' u/ S' v3 ?9 `
- else
y, r- p2 g' [ G, l4 f3 `# \ - if (socket != CONNECT_POOL[user])//当前对象不一致,更新: H, A% k5 x2 |! U
- CONNECT_POOL[user] = socket;
0 V5 A9 [5 @) k- u- Z - #endregion
; X# d; y5 ?) U' M1 L. ? | - $ ?8 b; P* K$ y) V" B- v- P
- #region 离线消息处理4 T, f9 {6 v2 [; V7 m: @
- if (MESSAGE_POOL.ContainsKey(user))! v) r, R& v) W6 ~9 e
- {/ [* `# `/ v/ O
- List<MessageInfo> msgs = MESSAGE_POOL[user]; q1 j/ O+ S0 ?! k8 x, k
- foreach (MessageInfo item in msgs)
\. b( s1 u& a+ r4 n8 Y - {! }4 Y) J7 L2 Q: Z G* m/ L: u
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);4 K/ v1 {: M; q( ~3 ~
- }
# D1 R0 Y N: b% Y e* I - MESSAGE_POOL.Remove(user);//移除离线消息
0 {3 q& W& r4 q4 q, {$ W! J" ~8 a - }3 W' C) }) |' _# j
- #endregion
% k8 D y5 G3 I+ Z) Y6 f - ( }1 D" B8 S, m* I: M5 H @
- string descUser = string.Empty;//目的用户
4 f* T: d( {: ?6 S - while (true)7 f5 M4 A' K9 ^# `2 Q1 M. [
- {
7 w% E& m% _ R0 y2 c* n: @1 T - if (socket.State == WebSocketState.Open)
9 P0 C/ q: K8 F* e - {% L! K. `) G/ V' {# F Y
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
$ U* e: G% q/ {" G9 {- j - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);! D3 ?$ H4 D! L; y# @
% t# {. b6 N0 @- #region 消息处理(字符截取、消息转发)
: W! `, L* {, g+ G; R6 \ - try8 O9 e+ Z8 O6 \0 i3 u3 [$ h8 w/ e
- {5 `+ N" o. `; a. a. \4 d. c ?
- #region 关闭Socket处理,删除连接池( L0 P3 U) O( \. x! s8 i2 l4 u F
- if (socket.State != WebSocketState.Open)//连接关闭
6 V3 K2 K3 e! C8 d6 D; W5 N, ?6 J - {
) s" v( x: D/ ?* U - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池4 Q7 @$ w2 V6 ?% n% j9 | e# t; g) Q+ x
- break;5 M- d6 J8 h0 L R8 m
- }0 `4 G2 I+ ?( U- Y2 F
- #endregion; b/ i; _* r# e# K& Z2 |; D
- ' }8 ~& n$ c2 t4 W. `
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息3 J) Z" L. ^1 X
- string[] msgList = userMsg.Split('|');. L: @) }8 j1 Y# e$ P r& z& K9 S+ V
- if (msgList.Length == 2)
, m, d4 o) N" d1 I5 o( K: A$ X - { F6 f: s5 P4 W+ A9 C1 O
- if (msgList[0].Trim().Length > 0)2 ~' O! s) ], _
- descUser = msgList[0].Trim();//记录消息目的用户2 ]9 K* A) H. O4 ]1 q% u" G
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
/ X: ?4 X6 L) E - }
% Q$ _* U! M: u- n - else
+ u! ~9 K( W% \ t7 G9 t7 {& m9 _0 B - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
; e; n A9 t* |
# R7 I% ]# k# g' r& e) R- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
9 [8 b6 ]: ~% Z - {) ]5 ]! v6 H, M) l: T8 j( A0 s
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端 ^, h: w9 L% ~
- if (destSocket != null && destSocket.State == WebSocketState.Open)
+ i( v$ s# S' N! w - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);8 e2 h. l! U# Z/ e5 }; C! b
- }
" F' {( z7 B- Y: s3 E0 y8 B1 |1 [7 Z - else
# N5 a, g# V7 C0 l) c* n5 } - {
V/ T$ ]4 x" u& H - Task.Run(() =>
" n+ }& h4 I1 T" w" P - {
: G1 p* R! }( g5 q0 ` J; c - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
- X! _6 X: k/ `9 _ - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());: z: W% h& Y! X2 ]0 `: m% }5 m
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息' g% l" l6 D9 t( A/ f
- }); C, m+ x2 l: l, G r6 l p
- }
K' m; u, R) Z$ n, i3 Q - }
8 r5 V' ^) G# v1 z - catch (Exception exs)+ K4 t! ]9 v8 q
- {& K s% A- B$ C8 Y, S4 E
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息2 n8 f9 x0 p9 A5 {4 c: d* D B( K9 d
- }
; v! n" S6 x9 O4 T: }; A# Z0 V - #endregion
$ W r- E% J. Q6 @0 h2 w% { - }% k+ d0 Z# p% l2 A
- else
/ L! Q8 ?% F: `! ^: ?; L3 Z" g q - {+ x9 i8 d+ ?2 e& r8 H; A, K
- break;; {! W8 d$ C: \1 Z$ t0 f3 V4 K
- }( y8 N3 v' H9 C, n2 t1 F; p5 m
- }//while end
0 v; G0 X+ |( l1 E9 l" s* O6 l. l1 c - }& \, p3 ]* g/ J! d& _! l1 a3 O
- catch (Exception ex)3 x/ _) V4 W( N7 q5 g" \& L
- {1 {9 u, e8 x$ o" g# g9 J
- //整体异常处理
& G, j% \% T* t5 ? - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);/ X0 v4 N/ ]" c
- }% j1 z% m- C2 _
- }% T& U3 ~' s* S3 Z3 [ r0 E# p# z
- # I+ L) X0 R2 p6 Z- J# o% ^
- 2 \5 x1 `* @% ?
- public bool IsReusable
1 [" y/ Z) N8 Y: Q - {
- a( x9 D8 ]! g$ z1 n! Z - get/ a1 B' ?3 v- Z T. G- B
- {
% u) |7 K% S- b: l# L) B0 { - return false;3 H! {( l, t: n* c
- }
( i B4 C2 N9 E6 n - }
8 b, P0 [, \4 d8 ^6 X9 j* A - }* ?5 j! e. _% R# ~5 d$ p" ]1 z
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 * Q# l, L: K, F H2 Y
|