|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 7 |/ _; ]2 d7 L' C5 Q
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;; A/ S# G. i5 T5 n& l$ e
- using System.Collections.Generic;
& a" X; J K v- b - using System.Linq;
( M" J8 p3 ?7 |7 y$ @6 O1 R4 i- L - using System.Net.WebSockets;
2 u. Q( e0 L* s" I$ D `& R - using System.Text;
1 e+ @4 N/ k) Z/ |0 N( }' `* H - using System.Threading;
% j, J2 ^( N- S, _6 V% ? - using System.Threading.Tasks;* q# q/ m* F x: c" v3 y) M, p
- using System.Web;; d8 G$ r& d2 f( e/ Z' Q
- using System.Web.WebSockets;
) N/ @$ p+ O' p: V
0 I; J# e$ D1 a
" v9 ]5 v# Y& _7 f* y& }- namespace WebApplicationWebsocketHandler
; o% {: W5 a/ u. [, E8 R6 Q8 f8 V1 E( W - {
! \- p6 ]! t, e% ]/ q - /// <summary>6 e- x6 n1 A: B6 G" O7 |( [
- /// 离线消息
1 p# C1 o6 V x( w2 q# c - /// </summary> O1 y1 V2 d+ B- H6 q& y! X
- public class MessageInfo3 a$ L+ E( N: C& a8 V# e0 p4 J
- {
/ i7 L* E/ j+ [ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)3 Z D' u) N: H
- {5 } I i# d3 b6 I8 f
- MsgTime = _MsgTime;
: `$ y: s( z5 O# W0 w/ n - MsgContent = _MsgContent;! I9 _* h' z/ j: ]
- }
3 |0 V1 N* j" p5 D+ h - public DateTime MsgTime { get; set; }
3 Y# L0 N- t8 Q - public ArraySegment<byte> MsgContent { get; set; }
9 x; [# K- b/ Q" { m3 o - }/ E" B6 L. o! X+ i6 P) a
& V8 S& I9 O4 i4 C) a3 u! ^
! k% e! r5 p. n& D$ e
, O3 w0 _- x s4 [% h! P2 x' O- , n6 b- `% E* d
- /// <summary>
" F. x$ I: L9 O) b# z6 K - /// Handler1 的摘要说明% A: J, } \" k% r
- /// </summary>
, D' j; J' M: m7 u8 B# u - public class Handler1 : IHttpHandler2 A. O% N4 I& S% G; B( `
- {
. d2 b2 b2 C1 L P! Q - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
7 [5 [: i5 `9 m3 L d6 H - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池 Z0 c: `9 B) Z
- public void ProcessRequest(HttpContext context)
- v) h+ i+ c/ E# F* M5 q - {. S5 ~9 r3 F8 s, b
- //context.Response.ContentType = "text/plain";
, u2 ~4 c5 D! ` - //context.Response.Write("Hello World");
$ n5 g0 U: N# I/ f - if (context.IsWebSocketRequest)
1 n% J/ @ K4 f - {
# B f# i" a% t1 E0 ~7 a% y8 T& } - context.AcceptWebSocketRequest(ProcessChat);
* N3 ~, I9 m% C& v$ k - }
# m$ O, ~( R0 W% B7 d' x; f p - }4 b+ v1 J; d7 k) }
- b8 S, r1 y5 `, f
- private async Task ProcessChat(AspNetWebSocketContext context)
3 H% J) B; b ?, z ^4 S! k2 U" K: z - {
) ]- x$ k4 H6 k- x - WebSocket socket = context.WebSocket;
; G6 Q1 c( Y" e: ?& ` - string user = context.QueryString["user"].ToString();
0 v+ z4 T. j' h4 L* v8 d
- V" t! m4 m9 F# G' {0 b- try
# X' X8 }! N3 Y, v - {
) ~: \# H8 J4 F) t8 [ - #region 用户添加连接池8 X# d" ]9 Z9 ~+ r& |2 g
- //第一次open时,添加到连接池中# p$ y) x7 t& q* _
- if (!CONNECT_POOL.ContainsKey(user))
$ F. A# F2 @* V0 u4 {% f - CONNECT_POOL.Add(user, socket);//不存在,添加
5 r9 k1 n$ l4 G) ]" j - else
0 O& I+ j$ X+ k - if (socket != CONNECT_POOL[user])//当前对象不一致,更新+ C7 @1 B+ F( T3 f
- CONNECT_POOL[user] = socket;
/ J, t: n: j. ?, U6 l R+ G - #endregion" z% U; K8 H5 g# @3 k
+ X1 k: h, }1 r+ u/ f- #region 离线消息处理2 q! S' N: m; k/ N9 q
- if (MESSAGE_POOL.ContainsKey(user))* P* i1 N' ^5 y" O3 ]1 C/ p# o
- {
# @7 k8 \$ m( N9 ]" B' `8 w - List<MessageInfo> msgs = MESSAGE_POOL[user];! q8 |3 W3 o5 p" q3 Q
- foreach (MessageInfo item in msgs): R. g2 N0 b4 R( U0 [) x/ ]) p
- {
4 y( k. { d9 I7 W; i, k - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);! |# N, n/ Q; b$ D
- }
}) `9 P4 o5 }$ J. ~; V) F! e - MESSAGE_POOL.Remove(user);//移除离线消息6 v. S6 E, g' K. i( P/ b) D
- }
" O7 l+ o1 Y J/ d5 h! d' y+ q - #endregion0 y% N. ?$ I$ u
1 C F! Z) ^1 d( X5 y9 u6 j- string descUser = string.Empty;//目的用户
4 w+ V/ I, h( j5 ?# R t - while (true); H0 Y! w2 f: i" D x+ C
- {( c u. \8 @6 [" M0 q
- if (socket.State == WebSocketState.Open)( ~* }6 c0 E) J: V5 Z* Y/ Z
- {. h; B8 b! o4 L& T6 |! i
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);3 B! m/ s/ n5 Q4 d8 ]; W
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
1 I4 u& e, v5 L; P" A% L9 P - ; d2 \- R6 d' f! c9 x
- #region 消息处理(字符截取、消息转发)* \9 Z3 a0 m: M# \4 h. V2 e! ^
- try
/ {6 r' P; x9 ~+ q4 ~1 _ - {
3 \) ]6 l) T' r) v' y; F - #region 关闭Socket处理,删除连接池4 v# K; Y4 P$ T3 K$ T: c
- if (socket.State != WebSocketState.Open)//连接关闭7 O! g }4 {8 C. A6 U
- {
8 ? I5 F+ \1 N6 o. e - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池1 `3 G7 b( X3 O) B
- break;: O# C3 H) U4 V( j$ n
- }$ u3 e- V! l2 P+ k% z
- #endregion
$ T; ?5 N0 S5 a3 j: u3 ` - ' g+ n+ [4 l* P2 D5 P( S
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
% l% j* X$ L2 A: F2 N- x9 V: h - string[] msgList = userMsg.Split('|');
5 R6 G& o' I+ a( |& c, m - if (msgList.Length == 2), k' J, Y; S0 H; l( v6 N" ?4 B
- {
( q" Y+ K, m; E" c3 R - if (msgList[0].Trim().Length > 0)& Q* \$ F0 i; a, S. I; Z. p7 l# Z
- descUser = msgList[0].Trim();//记录消息目的用户
+ o: i! N' z0 W7 Z( ^+ w6 {3 c: A - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));5 ^7 E* M h* r+ i) S: E7 ` E
- }' Y' i+ q" q$ B# z' ~% g
- else- k, a4 @ U3 p) ?7 Q
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));5 B- M& q2 M( x5 {/ k8 X' k
- e/ `( y! I8 q( g$ c; j- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线# B6 A5 o3 W4 F) r/ v
- {: H1 X, T% x: z5 x+ X
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端! z# f( S3 m" Z; r8 b1 c& S
- if (destSocket != null && destSocket.State == WebSocketState.Open)9 S" G) y5 ~4 J( j5 ]5 Q% Q
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);: g9 P: s) N. C" K* V
- }
# ^+ L! f. x/ j% r6 I - else5 P6 V: }* ^( G
- {& p) S2 V% j0 c' y
- Task.Run(() =>
; x/ T3 \ m( W6 }/ P0 p! Z" p - {' I, d5 x+ k( D; k$ h" U# W
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
' Z6 J5 B, U4 Z) k' |+ ]" D - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
3 y6 F- [& _$ p! M' I - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息+ ?0 w7 B9 Q: i2 y8 F4 J ^1 Z
- });
& D1 ]1 v& z6 q - }" R3 j; [1 `3 W: G7 M
- }
+ L: _; ?3 Z9 M2 Z, m- e - catch (Exception exs)
" D* m- e+ x+ `) {2 R6 E - {. c; {4 g7 |* t6 \! Y0 r: ^
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
! \5 L- N' R6 N( T - }
/ K, i( h5 g1 N& j - #endregion# Q6 g+ e* f4 p" u9 l# J
- }, u' A# Z/ I5 x% t
- else
) g: }0 {' V! ^4 i" Q6 w9 { X - {! v- E" h. E5 \! r- y2 Z& E; y" @
- break;
& H/ ]8 V( H- N5 r+ ^4 c - }+ C. s/ w9 p$ x- J
- }//while end
' w* F, ]* C: J; Y; `$ x; Y2 d - }% O4 `2 _5 F2 l
- catch (Exception ex)* J/ C- b& r( e
- {3 O7 x( Q, Y5 i W, f2 j7 l6 g0 ~ ?
- //整体异常处理
& Y4 H, h( W$ P! K R5 F - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
k3 _: {+ S' w - }
# N" x' n) e2 F% v x' b7 ?- T% |5 j- | - }
5 p. S9 w4 G3 a - & v0 ?4 o9 o: o! M& I' q
- ; A) @) c0 F) m/ h$ \' F7 J/ H) ^# ^
- public bool IsReusable9 i' h" v9 |4 W G
- {
, { [' } D+ |( S - get
7 Q+ P6 X- B2 \0 e# K8 Y: \ - {
9 V% o9 Z1 x. ?) o9 l1 r1 [2 L) D, B - return false;
C- \+ Z y& y- q - }
! K% S# M* E9 u: {0 f - }
1 G: T% i8 S: ?5 B - }! E* }8 q$ I2 D$ g: ^# d
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 0 X+ X0 m/ }. m/ T0 f
|