|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
5 K3 S2 o% P1 j% }; t0 _2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
4 b* B1 r2 @% c8 T0 ]" C - using System.Collections.Generic;- [5 r, \' h- L
- using System.Linq;* T- v3 m- g# E' S9 y* j6 d
- using System.Net.WebSockets;: Z8 n0 }/ t3 W5 c
- using System.Text;% V2 t2 F& m" v" I
- using System.Threading;+ {4 H, |$ T' J6 ~' N0 z4 m
- using System.Threading.Tasks;" e8 G5 k4 j) H% l9 n' I
- using System.Web;
( T- K, I$ B: H, N - using System.Web.WebSockets;
1 e$ v: E- f( ]) z1 I1 E: U
1 u1 S/ C1 Y% w9 @5 o8 F7 h& c9 H; |
: \" E; ^4 v& {# H$ o6 E- namespace WebApplicationWebsocketHandler& V; [) p% O3 O% O; H7 G4 G
- {6 ]3 q& V# x4 r. {% X
- /// <summary>
; \; {* N) C( m1 u! x% i - /// 离线消息# I: B7 F% _% h$ J$ P
- /// </summary>7 ^0 e4 _1 x( j- h7 [ ?% z6 q
- public class MessageInfo
7 w, Q) b: m( ^5 k4 r o: |2 W6 Y* B- m - {2 E0 p" Z9 w: W0 l+ C
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
/ Y- H0 k* ?! G2 P3 h - {
6 R# K- u2 t, C- n, z( S) F6 Q - MsgTime = _MsgTime;
4 a) Q9 I4 ?; t+ R( n - MsgContent = _MsgContent;+ U) g! d+ k1 N! D
- }
! W6 W' @: H- z' J& @ R" k - public DateTime MsgTime { get; set; }9 {6 s, X: g1 }* e3 K0 A8 [
- public ArraySegment<byte> MsgContent { get; set; }
0 G! e& I) m Y - }
7 s' o7 L0 ~; f
* e6 \) z( Y$ {4 n0 K- 5 e+ I, W5 @: v `( Q
- # j/ `. z, E: U3 O! U
h+ T( \/ ?& Q5 U3 V6 f3 a- /// <summary>7 y9 @- f$ X% S% [" y; u3 c% m
- /// Handler1 的摘要说明
& h Q- B* M9 n" B" r& Q - /// </summary>1 J$ m% W" ^" u4 c
- public class Handler1 : IHttpHandler
* I# g/ @7 b4 R) A5 d% S3 R - {& B" Y* H. c5 a R' O
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
/ W: V; k% F3 H" n7 q. U - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
& v2 h y& x, B1 H6 S' {% t - public void ProcessRequest(HttpContext context)
5 c7 I" I! V8 ?& L" f/ K2 c - {* o! F9 E+ G( q
- //context.Response.ContentType = "text/plain";; q% ^6 [, q! ^# k
- //context.Response.Write("Hello World");- s6 b8 w8 l* P: I/ d$ r2 N! B
- if (context.IsWebSocketRequest)6 E9 F2 j3 ]# m4 Z9 W
- {
6 W; G% B; D: I6 d9 \/ A - context.AcceptWebSocketRequest(ProcessChat);: o, \0 U) D! S7 f4 \) }6 {
- }
, U6 a5 s! W0 C; `9 j - }: `5 C* Q0 w( k
- ^0 [/ p4 _ j& G1 ?: D2 @
- private async Task ProcessChat(AspNetWebSocketContext context)
4 i! h, Z8 W2 c2 Z3 o2 d w - {+ P' x6 G0 B: a3 s
- WebSocket socket = context.WebSocket;" W* Z5 e- ?8 t9 `( Y! Z
- string user = context.QueryString["user"].ToString();
$ A5 ~; o- A l$ ] - t) p/ d0 G3 z8 B
- try! J/ C! G w' ~$ ]. F
- { a" |& H- t0 P
- #region 用户添加连接池" {: u6 V0 V G2 Z% X
- //第一次open时,添加到连接池中
1 u6 z! O+ Y% R( t) G - if (!CONNECT_POOL.ContainsKey(user))
# X/ \) i, m6 Z1 S9 F9 x - CONNECT_POOL.Add(user, socket);//不存在,添加( x: w8 N8 C! F+ t5 x. t& J
- else1 P* B. ^4 a, u% Q4 ]
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
- t# ?5 }4 L- G7 Y' a - CONNECT_POOL[user] = socket;
% ^2 |, ~6 f$ \3 C - #endregion% `/ a7 o8 S9 g0 P5 [4 n
- ! }; L- @& y' ~% g( k
- #region 离线消息处理- H' t+ R* D3 M
- if (MESSAGE_POOL.ContainsKey(user))& _( V) f: X% F8 Y5 k
- {, e4 `; Z4 A2 s* I' ^: [
- List<MessageInfo> msgs = MESSAGE_POOL[user];+ `8 S& m3 d e- T: m
- foreach (MessageInfo item in msgs)
5 _* x+ k* E' w& o - {2 S) O0 Q4 J Y
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None); R& ~) T6 F0 @: e- G5 F: B+ u/ U
- }& T7 {6 n/ F& i9 n d
- MESSAGE_POOL.Remove(user);//移除离线消息
) h8 q2 f; m% v2 | - }
0 W9 p# n: [6 i3 n% e - #endregion
5 M) q& F1 `# r0 `' Y% @4 j- _ - 2 x4 A! w- W5 }* G
- string descUser = string.Empty;//目的用户
! S+ e( A! v$ W$ X' `: g - while (true)4 k' B* ~; h$ P# p! A3 r
- {# c- l; w r' `- P# X$ C7 I) w
- if (socket.State == WebSocketState.Open)% Q6 q, m# Y! \' c9 g9 J; C
- {
& p9 k( i9 \+ k; X - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
7 ?" H3 j( |- \2 ^8 ^2 B - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
& s1 G1 s' s- m: m
; m0 [( o, q0 Z: M% z8 ]5 y2 A- #region 消息处理(字符截取、消息转发)0 _4 G# \ v, m" i, a
- try0 a5 f( o1 }% g7 B% a; R& ?) ^, D
- {5 @& g; x5 ]: H. m$ b
- #region 关闭Socket处理,删除连接池$ K, z: t2 q2 o$ U
- if (socket.State != WebSocketState.Open)//连接关闭
: {7 B; T( T0 `) r - {
; m/ [ N! B7 [% c4 I {, E - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池. j3 b- e( S$ t2 L
- break;
: n, ? P& X8 _$ Y2 a2 w; L5 d z2 F - }1 j) w( ]+ B8 @3 z) u( d
- #endregion
; [# P4 r, g! f' J3 A7 e# [) T m4 ~ - , @' e. n' q8 @
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息4 G& T5 J& l4 G; R
- string[] msgList = userMsg.Split('|');
) W+ x' r: P$ b6 t - if (msgList.Length == 2)* S1 }- }, A" ^' k! P5 Y
- {& @4 }2 i6 V5 f
- if (msgList[0].Trim().Length > 0)/ G9 K; J/ B5 S# B7 ]- i" `
- descUser = msgList[0].Trim();//记录消息目的用户
% P M; W8 O/ _+ b0 U - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));8 z3 s `: Z2 C
- }! M6 Q2 D' Y6 [5 `: d0 Y2 Y
- else
: U6 v* \# ? |6 y# O( t - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
0 m0 ]! f5 z9 m) q6 n: s" p
/ h+ A1 ?& K* h3 Q8 a' A" |' J- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
& y* w/ y9 g2 P6 O2 P: K - {
4 p# J& L/ `; u. B - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端 O! N; y+ M2 h9 o. J# S
- if (destSocket != null && destSocket.State == WebSocketState.Open)
6 I9 n( R. h- U- X& R - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);, J: l9 t+ a) Y$ F( k: j. D0 o5 i" j
- }) b! Q8 @6 {6 r
- else6 S0 `+ e- V( e
- {5 y% Y1 u6 b0 \3 l6 i/ w
- Task.Run(() =>
" F; g: D. ~( m% M# c2 [" x4 U - {
$ k0 ~) T9 [! ~$ z, m! c$ U ~ - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
; _+ A+ t( l% R0 m' l' X v' W7 E& b - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());& |( Q7 p* ^* w. _0 ?; C3 n
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
% f, w9 g% Q2 U5 B& c - });4 ~" O6 w4 S3 h8 c) G
- }4 c2 p: p2 ], @9 h5 J: ~
- }
& V3 @ B2 j* D/ p. o. g" r$ h - catch (Exception exs)
8 @8 ?. F' B; v! `6 T* F - {# I. p! w# V* z3 A
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
5 w3 k; ]9 `9 i1 [ - }
2 W7 k/ M" ]2 |$ B f* T - #endregion m6 w7 I# e4 n
- } Y6 a# u/ e& P8 z
- else' f9 L4 I) ^. u* I3 n& [
- {
4 W2 m1 {, L* a& C3 x$ | - break;/ h$ l1 R6 }3 q/ J
- }
/ g" j0 k. k+ q7 [. a/ g/ i" m - }//while end! `: t U% l, b7 q0 P! i, }
- }5 G( g0 k4 n) A2 |
- catch (Exception ex)
6 u$ u8 P( n1 G7 j4 f - {9 x; e) @9 ]4 Q1 E2 o! q) r
- //整体异常处理
5 q" Z& u& \. X0 I: e1 j: l" y. b - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);" E) J4 t9 A. h1 t7 F) O: P
- }
$ X; v% U) K( p' d4 g, b/ ^ - }4 Q5 G3 _( i4 G; K5 i% C
- 0 I' d2 p: O. s9 _8 f- @
" C" m. H) |/ R' L- public bool IsReusable& s, U3 y( V" b i/ P
- {
0 v" V0 e5 H7 j% N: A4 M( r - get2 P U! T s4 V
- {
' G6 o8 N4 s' Q7 b - return false;; L% z& p# _, R
- }; G4 s* y9 _1 j) p3 U) S) @0 ^0 Z0 ]
- }# P: \6 f1 S) G3 C. ?
- }' g" }0 C p, W8 }; Q s" e0 V) m: `
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 0 t/ O/ F9 E! k
|