|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
1 c) w0 z- \3 a4 |: l H- N2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;; D+ W% k- r8 R
- using System.Collections.Generic;
) A% s0 e l: q$ C6 o - using System.Linq;
! F+ H" C5 j1 I: r/ O - using System.Net.WebSockets;
; S. l# s) d) M# ?" O/ T' I2 ]; r - using System.Text;8 A) ~* g* V4 C) A& N
- using System.Threading;
& N. }1 Z# K! Q1 g8 ^ - using System.Threading.Tasks;$ b# n7 p* z1 H1 [& |$ y4 z1 e
- using System.Web;
4 ?7 n8 V* |+ b! ]/ w - using System.Web.WebSockets;& R: Q/ H1 {& \9 h3 \: _) J6 n: R
- % h+ n4 j; c7 e7 x3 S
- 3 A! s% y( C* g6 g
- namespace WebApplicationWebsocketHandler
! L) H1 B6 ^. [+ X& D7 w - {( }5 {. @* D( u8 W$ J7 \ Q/ V
- /// <summary>8 c8 _" A6 A7 n% `
- /// 离线消息, j5 a9 a4 L% w; P
- /// </summary>
+ h$ V8 D7 Q, z4 K( Y - public class MessageInfo
) i# | M* b6 V, ]. ? - {; m. [4 ^* E X6 s. e0 n
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
' R* ^) v$ {& Y- p5 z: _8 K, Z - {, ~( f4 |& |& B1 }
- MsgTime = _MsgTime;4 A2 `0 B# T! t. G% h1 b
- MsgContent = _MsgContent;9 B) V: m$ F6 Y
- }% o% E4 B3 T# @: L7 v
- public DateTime MsgTime { get; set; }
4 P6 a' Z/ N% v) j - public ArraySegment<byte> MsgContent { get; set; }0 J6 ^' Y" Q1 J
- }' E2 C. c' a/ d2 l( }7 W0 d
- 5 Z, q8 f# f, H( h9 a5 O
$ \+ @" Q D4 \+ y2 Z- 1 \* i$ q i% G% v
, ?' e1 E# E2 I; Y& s- /// <summary>' V" a: T P2 Z! q' j u7 s. V
- /// Handler1 的摘要说明9 t1 p' v6 x3 }
- /// </summary>
" z! W0 ~8 y7 E% w s7 z N( X2 w - public class Handler1 : IHttpHandler
0 J2 a3 k5 b: E, j$ ] - {8 @* V, K+ O* `+ i% h
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
! d$ K, n& U" F9 l - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
# [4 A. m2 k H: Z! | i - public void ProcessRequest(HttpContext context); d q- u% s: n" k( V" W
- {
. r8 ? t* h7 v9 d - //context.Response.ContentType = "text/plain";& t1 g" M6 [" A4 V+ T i
- //context.Response.Write("Hello World");3 W0 |; M5 k6 f a; _+ v/ f
- if (context.IsWebSocketRequest)7 x9 l' B$ O8 }0 F4 {- h0 T8 C# T
- {
4 s7 ]; [8 r9 d% N4 @ - context.AcceptWebSocketRequest(ProcessChat);
! Y1 h# L+ [, n2 c G. A$ E0 R - }
- T5 t5 O; @6 ^9 ~% Q+ l - }
0 ]' ]+ Y5 j# H0 g' f. t. @ - ( ?; f5 H( p2 Q# B9 e/ l) W
- private async Task ProcessChat(AspNetWebSocketContext context)
. ^1 b6 `* Z0 Q. m - {) V& U( l3 E1 G' l6 i8 v! k
- WebSocket socket = context.WebSocket;
5 `& N4 o n. G4 W5 f - string user = context.QueryString["user"].ToString();+ N% G) \1 r: ~' f7 e
- 6 X% c: p4 s p6 F- h' I9 _
- try1 a- C- V- Z3 D
- {
( p. }/ z5 o7 X1 p" ~$ C. W - #region 用户添加连接池; y7 q. n# g6 Z% }9 W5 G
- //第一次open时,添加到连接池中8 y5 D; G/ C7 v; n. ^% p
- if (!CONNECT_POOL.ContainsKey(user))
9 X" a' o" M8 F7 D& i. N4 ?8 L4 U5 t - CONNECT_POOL.Add(user, socket);//不存在,添加- [! @; e }1 h' w
- else
% Y0 f/ q# B' W+ S6 L+ q! ~ - if (socket != CONNECT_POOL[user])//当前对象不一致,更新0 W/ w7 |" W: e
- CONNECT_POOL[user] = socket;, S) L' K9 ~( T8 {) y
- #endregion% S9 P0 H6 l. f1 h$ F
$ x* ?6 z# W# A: K3 u- #region 离线消息处理4 u j5 z4 H# H j
- if (MESSAGE_POOL.ContainsKey(user))
) W. c4 X8 A$ ~% \) R - {
, S7 a. S' P5 V - List<MessageInfo> msgs = MESSAGE_POOL[user];$ x3 S' w9 l( B
- foreach (MessageInfo item in msgs)
0 M* ~% _. @0 s+ g! r. j; ] - {* Z/ l3 O3 V" R8 v$ R3 D
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
" u! e" J0 H( |. q% K: g; c - }4 J8 K' s% `2 X8 f5 n( c+ Q3 V
- MESSAGE_POOL.Remove(user);//移除离线消息0 u: f* D2 Q9 \, F" T0 O& U
- }
8 C5 G) w1 g& v - #endregion/ s6 W) K6 e+ V
- 1 D3 i2 C/ w1 {$ F7 Z! x2 ?& x
- string descUser = string.Empty;//目的用户
/ ^$ t: S4 f4 C - while (true)3 c2 l0 e6 e# A: ?) Q
- {
2 i6 @4 x: Y6 m$ [ - if (socket.State == WebSocketState.Open)5 s6 N% l% r' [5 c+ T9 s
- {
0 b0 I( [3 l' `3 Q- e$ D - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
5 h. C$ I% `* M2 L7 |, F0 g - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
/ L/ d$ c' r( [: R0 d$ }5 c
& u& Y n$ e2 j- #region 消息处理(字符截取、消息转发)
+ k% P" P/ g d, w' L3 ^6 @% h - try
# `- `' Q/ Q e5 a, g# F/ W - {+ s0 W; X# u& W- i! N2 b
- #region 关闭Socket处理,删除连接池: M h) {7 K9 r9 u4 W2 A. ~
- if (socket.State != WebSocketState.Open)//连接关闭
6 n1 h! p& ^$ \! n - {
b5 ^5 t' V9 B1 m* _: k - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
$ F' C+ S- I9 t/ O9 u/ L8 z4 v - break;
' o! r+ D5 H% h - }
* k3 O3 C: i* n( @- ` - #endregion
! G( G( ~: Q1 e( i. ~ - & Y! u. ~+ _; ~1 H. c* X
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息 Q# w5 f: O, a
- string[] msgList = userMsg.Split('|');5 t+ ]' u1 A% U; Q" ]. a! M* M
- if (msgList.Length == 2)8 c5 `3 j" P, d- m6 r) `
- {( `/ i [. l( J
- if (msgList[0].Trim().Length > 0)
# w8 [ I8 N9 z7 G7 h, B: E3 o - descUser = msgList[0].Trim();//记录消息目的用户
& U/ e% ?. m2 s5 n @" z5 R - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
: m& e& w! x1 z; _1 W" | - }2 U% W1 j3 u( T8 g0 M
- else% ~6 t: J- I) J* p1 j: U- n
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
) W( _; s7 [. M" J( X" L* P4 o! h5 T3 ]
4 C, x: C/ x8 M( D% n- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
' M( E- G& m9 Z3 F' Q - {
" B4 _% F4 _0 q. t - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端4 R) x2 D. u. y7 f5 T- k2 X0 O) i
- if (destSocket != null && destSocket.State == WebSocketState.Open)0 ^ p: h" m$ H& X6 y6 B* O. J
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
) g! o. o7 Z ] - }
) H w% e+ C+ i, l - else( ` z Z, s% H8 o
- {7 k H6 g' x, f( u+ T
- Task.Run(() =>
& K) x# j/ c8 C- q - {
$ ]0 d7 q! q' L) p% o4 \ - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
+ P1 n+ [5 z, Q3 z- A5 C6 @ - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());! ]5 s$ l4 M+ F7 n
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
; |3 Q* F: p/ ]: a9 p3 X, ^& v - });
' R8 F7 Z p3 w" U - }7 ~) o% O0 I7 v9 F
- }
# w) l/ B8 u$ L. z; U - catch (Exception exs)
: U: |4 e; @' X: W/ Y b - {
+ [" E& [+ h. H J" J, i/ T$ ^ - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
" \/ e4 Z& p5 K2 m8 N - }8 N! K7 A$ t% m5 j0 `
- #endregion1 y- j2 } ?- A: B" S v8 m. y
- }
" h& x5 j+ {1 W5 \ - else
: U- K; i! x, N- k' C: N - {
9 ` c! M1 G4 k# \& F - break;
3 E2 ^* r$ V- {# q7 q - }
. y; m) z$ ^" {5 f7 v - }//while end
+ I, E& L( _5 K5 Q' G* F9 @5 z - }/ [0 t! H' [7 B) l2 x
- catch (Exception ex)
7 E/ a8 \3 c3 V8 { - {- i, \4 z9 r) O( q+ }
- //整体异常处理* G* q5 {$ w/ v k- [! G: A" e
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);( H5 i# P3 a, A1 w
- }
4 H4 g9 `2 S" c - }
1 M, ]; }; `; D T% d3 O - / b+ a% c4 N5 R
! Y1 K- {# D; f" [' ~: @" z5 a& e- public bool IsReusable6 G1 s) `9 W9 ~) L$ t1 F* T
- {7 k6 f$ M; g0 E& t4 I' ?; \* I
- get6 z/ {0 N0 _/ E! M# }% n
- {# y( s1 U. S7 ^6 W
- return false;
' e; X) v' C. M' h/ @ - }% K+ ~- ?3 A/ ]& E9 W
- }
4 J2 e) \( F) K4 _0 t# ] - }" R* Y9 Z+ ?% W% W, a" l2 y/ Y/ v3 a* O
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
2 O% ]- X- I: F# _3 { |