|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 % m$ N1 ?' q, s
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;5 I h4 B, H @6 `+ F- E
- using System.Collections.Generic;
: C( i1 n4 E: Z g8 L3 y - using System.Linq;/ l! U+ m/ G0 ]
- using System.Net.WebSockets;/ U3 r9 Q. Y( g8 C1 Z# n) X
- using System.Text;0 H) m% ^! E% i# D; v- m
- using System.Threading;7 l8 \& P+ a1 T
- using System.Threading.Tasks;
8 e+ n. L6 d& F6 _% M0 o/ W - using System.Web;
( [) |) ?) L1 k, X8 N! C/ C. j - using System.Web.WebSockets;# {. M0 J& }% A% ?# E* d+ x
] v5 g; }5 ^# Z- 6 J/ W/ J( {8 @* u9 [/ m$ A
- namespace WebApplicationWebsocketHandler4 a" y& a+ `& v: v4 c( `$ p& O. _
- {7 [$ Q0 X+ x% |+ u
- /// <summary>" h) | f: O1 H/ V: [ F
- /// 离线消息( e5 A/ @ t9 [! [' K3 N
- /// </summary>" k2 q% A9 f7 \5 R* ^. m
- public class MessageInfo. Z4 s. O3 V5 s, B) v" `4 P+ m" |' |
- {
& O2 c6 N# C6 o q8 ~ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)2 r+ ^2 K+ T: b( W8 U1 c
- {- g3 y; s) J0 i R! {8 i2 l( k0 F
- MsgTime = _MsgTime;
H9 }3 j( x1 G( o% K; A! Y/ P0 O: E - MsgContent = _MsgContent;% _ i5 s' L! b: E x9 c8 ~
- }
$ ]9 N' N9 V- o: H; l( p - public DateTime MsgTime { get; set; }, |3 t; c6 c3 u; L
- public ArraySegment<byte> MsgContent { get; set; }
4 u. P% d9 b' ^8 W& S$ T. \, n& g - }! W7 g) ]1 w X1 d* b4 x( x
- 6 m2 S$ u. R7 q/ H; Z% {& f1 E% \
- $ |. V2 t+ ?6 `" m8 V5 e4 ~3 h# W! H' a
: w7 B& q) m) R
- q% m5 s0 W' s( J& M1 i8 z- /// <summary>
, Q0 E$ [, m- o* R6 n) N' J - /// Handler1 的摘要说明( }9 }' k4 j+ e% ?7 f
- /// </summary> h4 R2 J9 y9 }# D0 g6 ^
- public class Handler1 : IHttpHandler- W; j- k. t1 R0 q6 R
- {9 ~1 J Y4 I( _0 I& Z. S. S( t
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池2 _$ F Y1 u' y: P3 Q+ t$ ]3 o
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池+ B, Y; @, z6 c/ F9 _' w
- public void ProcessRequest(HttpContext context)3 u* _) m7 q/ S3 q7 r1 n; r
- {
8 D4 }) A) l U) s0 i/ j @" Z6 b - //context.Response.ContentType = "text/plain"; n" Z- R6 e# p1 G+ ^/ u1 x
- //context.Response.Write("Hello World"); b. j; \( y) n: h7 l
- if (context.IsWebSocketRequest)
! \7 ?3 y* I9 I O) O - {
/ E/ |( k$ L( H; M" s0 P" W - context.AcceptWebSocketRequest(ProcessChat);6 a& u3 ^8 k, f4 b k
- }
8 f# a$ L( K- @" a' r7 L, ` - }
$ M& \* K2 k6 N& P - 5 F) K, D3 P" l4 d; a8 g# I, \% B+ `
- private async Task ProcessChat(AspNetWebSocketContext context)
' G& |( H) n2 {9 r% y, z - {/ n* a2 }: y6 _& m' [0 }$ I
- WebSocket socket = context.WebSocket;
- R) f* z' z9 c2 y- V" u" r - string user = context.QueryString["user"].ToString();- x1 K' k' [) w5 | s4 @
! J; f' s2 q6 X# F3 A0 Q) }- try( P5 m2 C4 V& q! C8 {0 O9 H
- {8 i# b1 y) G# R
- #region 用户添加连接池% c6 R l. L7 R. f1 W5 l6 ^
- //第一次open时,添加到连接池中
7 l& e9 I4 h& \- g9 W- q - if (!CONNECT_POOL.ContainsKey(user))( k% l' G& }: R
- CONNECT_POOL.Add(user, socket);//不存在,添加 k* f# J, {3 @4 v: p8 }$ F1 K
- else; Q4 W- |) r6 b2 h$ o; B
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新8 S5 n0 R# J) I) I( G
- CONNECT_POOL[user] = socket;3 @1 G( J6 o% H
- #endregion
9 K3 a+ _0 z9 u+ S6 O: K' t - ) F& c3 y O) v
- #region 离线消息处理
' t% x, o- ?2 ?- L! Y - if (MESSAGE_POOL.ContainsKey(user))2 A7 y* Y5 E9 |+ I
- {
1 F, o4 z( N( H& c: W - List<MessageInfo> msgs = MESSAGE_POOL[user];
. l3 c Q, {- D7 [5 t - foreach (MessageInfo item in msgs)
4 @8 b. a4 C0 Q5 t5 v0 ~! } - {# G* ?2 I4 I/ o
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);! }0 c% r) d2 D/ ^% e
- }6 l0 n1 q: _: } U
- MESSAGE_POOL.Remove(user);//移除离线消息
0 o' O7 h6 c6 t& A1 J: h. L: T - }+ |4 J' R1 b4 a: X! T& N
- #endregion
8 v, j; k$ T7 |0 H. g
: G$ p7 B/ T% i' R! G0 W( X- string descUser = string.Empty;//目的用户
+ E, K, M( F7 F9 i0 y- [$ _ - while (true)5 Z( i4 F% P( r* Y% F7 v+ ?
- {7 [0 @' Y0 H/ g
- if (socket.State == WebSocketState.Open)
( D# M8 F( M2 Q8 p - { g( C! ]2 f5 Q# v6 ~$ y
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);* r( @5 a, V7 @
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
" `) ]% F/ V& u% G. p7 l1 k - ; D6 p' M, }: r6 ~1 H+ e
- #region 消息处理(字符截取、消息转发)
3 V1 ?- c8 X1 r3 \ - try
1 e" l! T# B# ?) s7 R/ ] - {
- x! c4 P- o) m4 U$ r - #region 关闭Socket处理,删除连接池
6 e) a4 o, \# j - if (socket.State != WebSocketState.Open)//连接关闭" { J. a$ @) }8 c
- {
. `5 q( \' p' l" l/ x$ h/ j - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池0 E, Z( S2 @( G5 K
- break;
- C( @) B% [5 h2 {6 |- h6 e - }9 q- M7 p z( N3 U# g( b2 H/ d% {
- #endregion
: e: L3 g% T' | n# w/ g5 H - 5 Z; E. @$ k2 V6 H; U% g/ x
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息% ?& k, p: Q% H G7 u
- string[] msgList = userMsg.Split('|');
; c; |0 K2 f# Y; f- y - if (msgList.Length == 2)
9 }/ i; _2 D0 u, M - {9 ]1 s4 S8 f! l9 p1 M1 v
- if (msgList[0].Trim().Length > 0)/ Y8 o3 \6 V$ ?
- descUser = msgList[0].Trim();//记录消息目的用户
, `; U0 L1 D' j1 U - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
8 w" j/ ^+ y9 P/ i1 B( l - }: U5 X! D5 k1 f' C! S7 L
- else% A' B6 r; A. X+ q
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));5 m; n4 P; j4 m. [
# w Z0 u% y/ B+ ?2 x; S2 s- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线! ]. n/ ]1 w& G! Q
- {. v2 A6 [/ P. B. W
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
3 {4 f# j% E0 ~: v# y0 L) a7 b - if (destSocket != null && destSocket.State == WebSocketState.Open)* n& c! v; E& g$ C
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);' P2 A/ i, R' @( O
- }
' u4 d" L; m, A0 l6 ~! M - else4 {# h5 W4 x$ }$ x) J" v
- {
/ ]$ v% Z( {8 ], ^7 t - Task.Run(() =>& H; m0 @& H6 U
- {) m5 c* n9 o& w: Z! q7 H
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中- i- x5 V) w x$ x; a( @# |& y
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());8 V. A/ a# M% S4 ^# m
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
! t9 O- i* {* j% m& ?% B7 p8 C - });+ i% ?& f1 `4 `
- }
3 k* {4 `: f9 I. L' w3 k+ h - }
& i# U' X9 L8 n- E* ?% S5 ^ - catch (Exception exs)
( U* k3 h( n. s - {& E# l7 V6 c. J% y+ }" E
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
6 @8 c' q* Z; P" H9 p0 j. b - }/ [% y: i% R; a% Y: G( L- L1 O# h
- #endregion
8 _" B" L' `! g3 h9 G0 { - }
/ }# B- B# o4 F- W( |! c - else
1 U. o$ Q! H: j5 J k- T, m - {' O% K3 T! x* o8 q" X0 m/ s: Y) R
- break;
/ l0 p* E T2 `- o: l# y" `+ E& } - }/ w$ O$ r3 h# \6 D. s+ L
- }//while end. ^ s& V- P; _8 @
- }2 Z1 D2 W3 R# _/ M# ]; ^; ?5 p. D0 A, S
- catch (Exception ex)
2 ~- |/ A7 x! \# f5 R Y# B - {
, w/ a- n; g$ f - //整体异常处理
/ a' X. b- i5 g6 I1 K& E$ u - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);1 d f" C7 s; s, _2 ^- I: b& w) y' i
- }
& i: ]% k) J: r - }
4 ?% e4 F2 a" K - ) O+ w5 H: T, `& E/ `
- . T7 A1 D( T( W0 _8 f
- public bool IsReusable
# {9 f, M1 X9 K7 a6 u( K9 T - {
% N7 t- `/ N5 A: X* t9 `/ N* |7 {, Y - get
& \1 K. m3 T- \6 i1 Q9 |, ~ - {
+ p6 C; l7 s6 k. [ J$ N) q - return false;$ F' p1 R/ S& ?$ }, U2 h* ~
- }
3 Z0 h n3 f2 ^ - }
3 t* y6 ~3 d% K% [ - } l2 O1 C- g) V* C
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
S: ?# K x; u8 F% ]9 n |