|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 ' g! E, Y/ F6 Z* [) f5 N& g8 \
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
z) v9 n! f( ^. r( A" i; x4 Y/ I - using System.Collections.Generic;2 s: V, S/ n. U5 J% W
- using System.Linq;8 \* f7 b) a, ]. H
- using System.Net.WebSockets;
: I% [; [% e8 E3 M% C9 X6 s1 h8 m - using System.Text;7 A( t3 R C# O$ r1 T9 l' B6 V
- using System.Threading;
% O, a. I }; Z$ l5 b) h - using System.Threading.Tasks;
7 P/ r ?1 V/ | - using System.Web;
4 H Q# g1 d0 N5 y - using System.Web.WebSockets;5 W( |0 f1 z" [6 }1 G
' {) E0 p" ?8 N: {- 0 [9 [% d. n Y6 _, W) ~
- namespace WebApplicationWebsocketHandler
! ^% r; G# Y( ?: G; e# @, P - {
; `. o, v9 t' X3 ? - /// <summary>: C$ a! p1 p, H; ^; @4 o% T
- /// 离线消息, i: R4 O8 t9 Q
- /// </summary>) {/ I) ]% p9 w9 w
- public class MessageInfo9 ?. ] w' P# z3 U
- {5 f t! s* P @/ e; f5 T7 _
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
( F4 g: j7 I7 k: J' Y l {2 E - {
7 r' Z- u- F7 z8 ~+ N, b - MsgTime = _MsgTime;: ^5 g: o/ u* |9 C' ?
- MsgContent = _MsgContent;5 B' g" d! \( c2 z9 w2 m8 q6 b4 q
- }* S$ p/ y2 W+ Z2 \8 G- {" Y+ t2 V
- public DateTime MsgTime { get; set; }% o$ j# Z6 q8 Y2 }' W0 ~1 u: h6 ~
- public ArraySegment<byte> MsgContent { get; set; }
9 F9 T; h* J Q/ E0 p - }
+ T0 U; r9 E3 M' E - , o6 j( f$ q* w+ z
- - |+ r1 F) g, {3 Y, a2 N, ?
% o6 d% h4 z; k, X1 q/ S9 K- ' ?8 j# H1 M4 a& }0 g9 l
- /// <summary>! `9 H2 w, V% B: M6 G+ G) M
- /// Handler1 的摘要说明" g: I( v& ^: w5 P
- /// </summary>" \. o7 n) F# V3 C) ^' ~' S
- public class Handler1 : IHttpHandler" O" ?/ ^9 w; }6 I: R
- {. p8 @4 T: ?& n% H/ M w/ [
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
/ `4 L1 d0 A9 D1 F5 _ - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池# S7 D2 u9 e6 a, h
- public void ProcessRequest(HttpContext context)/ q# U* w; k3 _' _% N% q
- {; {; T2 v7 G7 f6 W- e/ O) c* v1 z! G7 g
- //context.Response.ContentType = "text/plain";
Q+ B6 S, S& L - //context.Response.Write("Hello World");& N2 z3 m4 B& o( G) B
- if (context.IsWebSocketRequest)* f. r, {% ]1 I& A3 i- ~
- {
; ]; u# k+ a" j$ Q - context.AcceptWebSocketRequest(ProcessChat);
$ c. l; u# j8 j# X) @' Y; O0 l/ h - } + {( c+ T( ~2 l' e1 s) A
- }- b# @# h: K2 B/ S* s4 ?; `& M' c
- 6 ]9 ^& l9 p+ b0 A* o% Y! E# T
- private async Task ProcessChat(AspNetWebSocketContext context)
, R# n+ k8 m* B/ v% q+ ?8 P4 O - {! j( v4 R: z! B4 O& @
- WebSocket socket = context.WebSocket;( s( M7 q, N" r0 f
- string user = context.QueryString["user"].ToString();
* ~: e! q- N6 u1 h C - / _" s; p6 L+ r! @! Q: y
- try
! `/ L, H$ T: T - {+ `/ x0 Y% Y* W3 \+ l
- #region 用户添加连接池% \8 d( }) C2 ]$ g
- //第一次open时,添加到连接池中+ [) x" f1 r% _: Z
- if (!CONNECT_POOL.ContainsKey(user))
+ |5 k: U% O. {8 n - CONNECT_POOL.Add(user, socket);//不存在,添加
1 A$ h7 R g7 [- x8 f - else
. k( ^/ K. h2 H, O& k! }, A - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
, e' u- b* C/ |- u+ \ - CONNECT_POOL[user] = socket;
5 e. {8 P; O: @: t' u# Q - #endregion6 j# J ?7 B# K- ~
( Y7 i/ G. r# d. u4 f9 M- #region 离线消息处理! J/ g3 F: H9 d1 G) G; T" S
- if (MESSAGE_POOL.ContainsKey(user)) A# g6 K6 e7 v% }) t# s
- {. `4 c! |. B4 d( l X5 q
- List<MessageInfo> msgs = MESSAGE_POOL[user];( T3 }+ k. E& _3 [; F" F2 Y- ^
- foreach (MessageInfo item in msgs): _% L C) q* r, |/ B
- {1 D: P4 b( l1 g6 ^6 [
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
3 r& y0 A( E5 G8 n/ C) P5 x - }/ p% {7 |% `9 C
- MESSAGE_POOL.Remove(user);//移除离线消息
# v5 J% n+ t! w& {, r* y( f - }2 I# [5 q2 \( k; q% l3 ?5 x
- #endregion- E' c/ I2 Q# X+ e. L
- / _6 |2 p! ]+ c
- string descUser = string.Empty;//目的用户
3 r! d, b& o0 w4 y% p+ }( ] - while (true)
% w' B1 @) V* a: O$ h2 v - {
2 f% T. B8 x4 ~& s" A/ C - if (socket.State == WebSocketState.Open)4 R' |0 s9 u4 U* \, }9 ^2 f. y
- {& c) \, t# N1 m& X9 V
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);/ V- f/ ^ d7 L
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
9 L. f1 q5 Z$ i7 d. [! P% _7 }0 p - - f: g# x: A; j Z: t: m
- #region 消息处理(字符截取、消息转发). s2 A' I' R S& Y, | g7 F- k5 k
- try2 _+ j9 d. j$ |. q9 M0 {4 A
- {- s* k0 k$ W+ N. K' n. S
- #region 关闭Socket处理,删除连接池" u, {% {9 a5 q5 C! L" Y( J
- if (socket.State != WebSocketState.Open)//连接关闭* I6 r4 N; @3 M9 i; z/ v
- {% W/ {. Z9 V4 Y$ }& |$ N9 }
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池! i0 i9 p9 f) \0 ]4 |) Q3 k
- break;/ _3 O9 N' V; ?, l
- }7 y" F$ P# m/ ^3 l B
- #endregion
8 n2 Q) e7 b7 V+ I: U; o1 p - 7 n# T, _8 j6 F; }% F/ z2 T* f$ y3 R! [
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息1 [9 `, O3 k5 z$ x8 {2 X
- string[] msgList = userMsg.Split('|');
6 X3 {2 B3 t+ I" U - if (msgList.Length == 2)% }+ L0 N) s# t* H4 J/ Y. `
- {
! K/ B2 b' V2 i% a4 L5 Z1 J8 N& G - if (msgList[0].Trim().Length > 0)
; G" p5 _7 u; A0 M - descUser = msgList[0].Trim();//记录消息目的用户
, S! n, s, k( W" @9 i- D - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
1 j! L3 K _3 V+ X. b - }
' f. N" {- C9 {5 A' v - else- l0 N6 [& n6 D4 V3 R$ ] q6 a' u
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));, I* J$ V# s2 ~! ]3 V
) j4 U' a3 H; K: u" B- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
) Z5 F( z3 D( k! j - {
3 j# i3 @2 D. V0 Q3 o - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端, P6 k2 O5 o! Q4 \4 x. ?4 s, @. z; s' p
- if (destSocket != null && destSocket.State == WebSocketState.Open)7 I0 w7 p" o. R7 Y
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
' f* B( N. o' x& U4 d: }& E& h - }5 p7 E! ~; v% {. I# b5 y& t1 K
- else
5 q. ?! x: O5 Z$ Y6 @" g - {7 v3 |! W9 r7 x! i
- Task.Run(() =>) r( e! V( F" c9 t+ a" o
- {5 I& v6 g" n3 _) Q
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中: w& C# |; |/ T0 ^0 ~
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());9 _% q; t) O- I0 P. f$ H
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息* T( l1 o4 V- `, i) o- x
- });
) r/ U7 v# y: P4 ^2 b - }
5 V; J& [' V/ f; T4 t! P# |- r# S - }" G4 p9 A' ^) k/ K9 c
- catch (Exception exs)" x6 ^4 j; m3 [+ j+ v
- {
" _) o2 u, c; h7 @$ I/ r - //消息转发异常处理,本次消息忽略 继续监听接下来的消息! p; i4 k! k8 f/ J4 c
- }
5 c" s" h1 B; g0 s, ~4 R - #endregion
7 v3 l, a x$ [0 s7 y5 C: T - }
! l6 J& _+ Y% O* ~4 a F I - else9 s" ?' T; N! _6 O3 S# I' y8 k$ r2 c( ^
- {. l4 K2 _+ v# o4 T9 j% j! ~0 F. [
- break;) m5 T6 [: \9 k6 \$ G/ Y; K
- }. T5 u- P) U, k0 o' p. c' E- B& y
- }//while end
3 b; t: `) v+ o' y) S - }
6 t. o8 W+ N2 v$ B. K - catch (Exception ex)
3 X7 Z* ]$ ]6 r# H8 f4 t" Z) d - {: j+ N: _6 n' r, D) x
- //整体异常处理4 o: h9 h( U7 Y( h" |1 e
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
0 R; q- V4 ?+ G5 D - }+ M3 b( I- O5 N6 r1 t9 H. s f8 a
- }
- R( h. F+ v' J5 A3 U - * S8 ^+ ~6 e2 b/ D( o& n
- 1 M/ I5 _- n1 Y7 Q" n- ? @
- public bool IsReusable
4 B+ N5 g# O; S% ?' T, x - {* o% Z- Z- c# Q: N9 u% z. n# \& b
- get9 A7 U: @1 s& ?: Z' P
- {
5 _6 t$ Y, t! J2 e5 m/ C* O( | - return false;+ E: `# Q {* T
- }
/ f1 R7 r! G5 |& l - }
2 o' x8 f5 L+ _; }6 n - }9 n3 t. x& U4 E+ w, w
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 7 V e, N/ l8 a1 i* O3 {; A
|