|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
* e" a( c7 c' n/ ?. q2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;4 V6 l3 j: X2 y+ d. A# o
- using System.Collections.Generic;
4 C: D# i( k; F9 f - using System.Linq;
( s) C' k0 H/ B. q" K - using System.Net.WebSockets;
& `7 u0 q, }# M0 V: z J0 [& C' [. S+ h - using System.Text;. J. ?/ V. }6 H6 \5 X
- using System.Threading;% H6 M# c0 v$ V% z1 r
- using System.Threading.Tasks;; V$ ]: R2 F! R8 i: {; ~
- using System.Web;
8 h$ i9 _. \* Z6 D7 K+ @) @+ G - using System.Web.WebSockets;
O* c* t& o. m - " O: f1 {' n A, I* p
$ q2 F% m7 w4 n' `% x' d0 h; ]- namespace WebApplicationWebsocketHandler
2 t& u2 f5 S. n' f. O - {
2 I$ T$ l; U1 E+ ? - /// <summary>
, S- C2 \1 V ?- d: V( r# o - /// 离线消息
. m- A: B% \& U3 c5 s; D - /// </summary> c: O h x8 r! ^ P0 [. B
- public class MessageInfo2 f$ H6 X. r8 H$ V
- {$ f* h1 y8 p, H6 m" ~+ B
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)7 {2 j$ R; x2 U# ^; M. e
- {1 v0 p' I* C, `9 v5 X% D
- MsgTime = _MsgTime;
. z1 z( B5 ]& R: o5 Q: c" N - MsgContent = _MsgContent;1 V8 k/ Z- j. F9 S8 d& E
- }$ r+ _1 A) J5 I: s. p6 ~* G# x
- public DateTime MsgTime { get; set; }. h9 f% l) r7 n4 v7 }- ~9 d
- public ArraySegment<byte> MsgContent { get; set; }
+ F- J. T0 v7 B3 ~* I" a: j& y; n; L* y - }0 E! C0 a* O; S8 W
+ x4 ? Z" M# w+ ?( I6 n- ' c7 b% U3 ^7 a# x& Q+ m( v! R
- p+ _2 u1 Z3 Z& s
( _3 y* Q( w" D4 Y, T: C# O0 c- /// <summary>3 m6 U- o+ j4 | f1 M$ b
- /// Handler1 的摘要说明: y/ T! x. D3 }; g4 h) m
- /// </summary>' A& [( j( x. F7 l3 w
- public class Handler1 : IHttpHandler' H* Z* [+ ?% h. N2 _# p3 V
- {
0 H/ |+ j9 d+ {+ d$ W- W7 B - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池2 X6 @) y) g, F
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
3 x( c" L# t1 c6 h, { - public void ProcessRequest(HttpContext context)
, i% t7 R9 a- V" t7 n - {
- P( ^, b3 Y ?& H9 C - //context.Response.ContentType = "text/plain";2 _5 t J) a) X: s. h8 X
- //context.Response.Write("Hello World");
8 j1 r/ o6 B' L! n; x( W. K - if (context.IsWebSocketRequest)
, X8 Q0 X1 c, J - {& |1 E$ j |% r1 s6 l
- context.AcceptWebSocketRequest(ProcessChat);! \* X" D' Q; t
- }
$ m; w9 _, r7 J( G - }/ ` C$ ]4 ?- O+ w
4 Z$ C; `2 r; h. ?8 [5 {- private async Task ProcessChat(AspNetWebSocketContext context)# |& o3 T0 A( y7 o* t. I) `9 E
- {# U" D, x8 }# {, J* R% w, T3 l- `
- WebSocket socket = context.WebSocket;4 d+ ?$ n$ g* U
- string user = context.QueryString["user"].ToString();
6 X5 N/ Q: B P1 Y/ x, [# w. e! L
2 P7 c0 R* q; g; F# A, S- try
( o. t) n8 k5 o - {
+ b' p7 f/ w) Z1 @. a- t/ T7 r - #region 用户添加连接池2 _3 W2 w, l( H; M5 g& r4 y9 V
- //第一次open时,添加到连接池中3 W9 d3 [ @! {2 r3 ?
- if (!CONNECT_POOL.ContainsKey(user))
' b+ X8 r' a+ K - CONNECT_POOL.Add(user, socket);//不存在,添加
; K& K, j% t. S2 ~. {9 c% d - else8 h9 B+ I, d5 E- q
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新) @* O( b: F1 m& Y
- CONNECT_POOL[user] = socket;1 \# s6 ^& i o$ j. [& W1 c9 J
- #endregion5 v& c9 \7 ]( H. k# O, J4 _
- & Z: q+ w% ]/ ~
- #region 离线消息处理! s4 o) \, H: A, V
- if (MESSAGE_POOL.ContainsKey(user))
; b4 A* f# v* b, X5 R- v% z, ? - {! ^, I. x+ d( Y4 D+ f
- List<MessageInfo> msgs = MESSAGE_POOL[user];
2 u- p! H* t; h - foreach (MessageInfo item in msgs)
, C1 x- u8 f7 o5 P - {
^3 \( b; y! h- g |7 c' E# t4 @ - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);/ T! E7 R e' |& g7 K( @ b
- }
; A9 Y3 V$ U4 W2 A - MESSAGE_POOL.Remove(user);//移除离线消息
, [8 n9 d; b; j, w! |6 `5 X: u- Z - }
/ h8 G- h' }6 K7 N* {' z1 V - #endregion
% |, t: U2 B& U' x - 0 T- p3 `5 d0 ?$ W8 `5 |& l+ T
- string descUser = string.Empty;//目的用户+ b+ V- [. N3 \3 r# `8 [9 p
- while (true)4 m7 C* L" m. W* P H0 w
- {
% W( Y7 e$ Z* l& T! c$ i - if (socket.State == WebSocketState.Open)
, V- k* s0 Z+ ~3 | - {) }4 }% J( g5 b4 T, _
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);# M+ V& P8 n- _/ j# U
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
, C- Y B1 N2 T3 ?2 P, ^0 C - 4 K, O! }, H) C. F3 S8 ^3 }0 Y& u
- #region 消息处理(字符截取、消息转发)9 D* v8 v- a- w" }, c: J
- try
" R, i6 m+ \7 h7 G' E/ l - {
9 |- _ v1 P# a3 q - #region 关闭Socket处理,删除连接池
( l" R% f0 W# H1 a- |% {% ` - if (socket.State != WebSocketState.Open)//连接关闭4 j( p, }1 O; I8 s6 B
- {$ D. i/ p. w! e9 F0 G8 V5 c- u( o
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
; P8 O# W5 a, T/ L& m" G3 R; @ - break;% A, L0 {( h7 W7 A" |$ m
- }) I |* ^1 P* I: p6 I& r+ `7 L
- #endregion1 B+ x8 F2 F6 o B
- u% F1 k5 Q( u7 r5 @
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
) X- c1 I; m8 D3 [7 X* H1 n+ W - string[] msgList = userMsg.Split('|');9 ^/ c3 e# d% I
- if (msgList.Length == 2)
* M; v2 Q1 b1 `# n+ h- b - {7 \# M2 z! [! p+ D7 F8 b" S
- if (msgList[0].Trim().Length > 0)
/ w7 z/ [, ^1 p, |, Y7 l - descUser = msgList[0].Trim();//记录消息目的用户
6 b" t v1 n$ g8 a9 ^; b - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
; a0 f7 _( m7 A* Y1 e - }
; S* b1 x: ]1 Z4 J, c - else
1 W$ \6 E+ n0 x4 e! V - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
; O( A7 y/ ?( {! o - / T0 R$ M" b+ R& q: _
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线! n) |& x( e0 T
- {0 W- L) t7 M2 N" A: M' e" e. C3 V
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
5 t* a* }. I7 G1 d9 |- X& a7 p - if (destSocket != null && destSocket.State == WebSocketState.Open)/ m8 m; Y" x% L. l" R, k( v7 A
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);" D7 n h- S& h3 g' M R% v$ \
- }9 r* ]$ x- D% s1 U0 P- |
- else/ T, I5 o& H, P2 Y, f
- {
3 O" C S9 m9 A6 E7 f) ~9 K - Task.Run(() =>. ]/ ^: T+ d& m3 g, n5 [4 y
- {
# }4 h1 r3 k; ]7 | q5 x - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
4 i; Y( o) n. z - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());% s8 e6 t) y8 b2 s4 \7 t0 R4 m
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息$ D& t1 Z* n/ L
- });
5 V9 [' R$ V# |/ G* v9 r - } z. z; \. G; z _/ j
- }6 s+ x( V5 J0 k0 \* p9 U) y
- catch (Exception exs)3 r) g: J3 p3 C
- {
+ n5 T1 y" Z$ L2 o - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
[0 u4 S0 d% R0 c0 ` - }
& w8 u! W9 u# ]0 i5 X" n - #endregion; g; n, }# n) S5 f& O" J
- }
e, g8 U/ Z* C3 z( G y ?) b# O: k$ \ - else
; W8 f6 C- b% u N - {
- t1 _* T' D- p - break; u! T+ G+ D4 ]
- }8 c& J; b( E7 c* M
- }//while end
% D! D5 ?5 L: u. ?' W7 x - }5 O% e% B; @: M* {) j9 E, p
- catch (Exception ex)
# b5 U9 v4 \/ F- J8 } - {" G! ?& V5 G0 `; h$ X3 N
- //整体异常处理
0 J$ G% I1 o7 J P! O5 B' a - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
. C% G! A' ~( J7 ^ - }
0 \$ ?8 M& k- ~, U2 ~3 z- n - }2 Y4 v. O. W) X5 w- f
: u; N8 z! L+ E( U- * {9 b4 d" [# Y
- public bool IsReusable
1 l6 N8 C# q) w6 |. z9 z5 w - {
) [: U+ S5 m: X5 Y - get8 q7 g4 T* }8 g5 y3 U' g3 t5 e
- {
0 f: S- V0 g8 Y% a - return false;$ y# B( @/ |1 p2 c6 }4 Y
- }0 m% Q0 c$ `8 j3 l0 V
- }, H! Q9 M0 I( u4 n" a! u& j9 _' J
- }1 S/ H0 r/ T0 L3 M! w9 {
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 0 z3 ]1 Y) R2 s6 \ U' f
|