服务器端代码编写 1.新建一个ASP.net Web MVC5项目
' d" K: M6 o" O F# I+ z) b2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
& C2 I( V1 m8 ?6 k$ ` - using System.Collections.Generic;
* R; L: D; m* |" I V - using System.Linq;
a6 B" ^* t5 B5 \) ~4 a; ?# o2 d% o - using System.Net.WebSockets;
4 g' o! G: t# d: U1 V' E& ?& y - using System.Text;* i% l5 b" D8 p: q+ x
- using System.Threading;
$ C" _% w' ]7 u$ ?4 F. k - using System.Threading.Tasks;
: k& L l# O9 V - using System.Web;; i8 J' G0 H3 [2 ~
- using System.Web.WebSockets;! p4 h& \9 q* ^( _5 O, Y
- ' v; v* |: x$ Z$ ]0 V: d2 {
- & i# C0 B4 O# z7 R+ ]* Z- S
- namespace WebApplicationWebsocketHandler
* E6 Y3 @+ }* U1 r - {
" L& k! G1 j" J! l - /// <summary>
% U" t+ I T- }3 _; H/ L - /// 离线消息
. }9 E- S0 w( y$ D - /// </summary>- ?) h( u# h9 r" x) O/ a
- public class MessageInfo# {# Z2 l0 [7 ?. \/ n0 P
- {
( x- g8 |8 x4 D5 ? - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
! P5 ~, j& B7 m2 e4 d - {8 R C, b$ `5 I( b$ X6 A
- MsgTime = _MsgTime;
8 T0 m9 V1 a/ L8 F8 H. m - MsgContent = _MsgContent;
. b8 ]. P1 H; Q) N - }
2 K, ^: f* H0 U/ T0 p - public DateTime MsgTime { get; set; }
9 r0 t- x9 o$ Y( G8 j! P( D - public ArraySegment<byte> MsgContent { get; set; }8 c9 G3 ~5 G" m- q2 L5 v
- }
% f" v4 C2 v+ |( a/ \
+ {4 R/ j: ?6 n- E# ]- ; [$ z4 }( e- b" a: M! h: v. w3 O1 ^+ V
- 9 U4 h$ ~) M2 N( L9 ~! V+ n
) ?& l- j6 Z- a% k. M- /// <summary>+ i; `4 g% } Z, A3 \$ z
- /// Handler1 的摘要说明
/ U) {. E) P6 ^& x% c5 }3 F - /// </summary>
" P2 k- c0 L [+ L/ D6 ~ - public class Handler1 : IHttpHandler
6 W" X2 y, T: ?, H# e) E - {7 W( e2 u: F3 d. Q
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
9 V% Z$ y" x- ?9 |9 {7 N: G - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池" W7 Q% t$ u2 K' N
- public void ProcessRequest(HttpContext context)
5 Q2 A7 ^4 w- j; i - {4 s$ _& |5 B" x' P* [" g& P* i
- //context.Response.ContentType = "text/plain";" _+ x- N) f' S- `2 s# W+ }) c6 _, _
- //context.Response.Write("Hello World");
& Q" ?: J( ^- |. f$ d3 s/ ` - if (context.IsWebSocketRequest)
, ?3 o( K. t+ O+ s - {
7 }; l: }' ^$ ^ - context.AcceptWebSocketRequest(ProcessChat);
: l5 E: j A: m* n% ~9 t - }
$ M/ C o- f; o* d) C- V3 v$ T3 V - }: z9 Z4 |; S m* g# q) \! {) U
N8 h" i" H) @0 `+ T* D0 _1 {- r- private async Task ProcessChat(AspNetWebSocketContext context)6 Y2 Z8 f: X |8 U
- {( z0 I, Y+ T! y: m2 c# _
- WebSocket socket = context.WebSocket;
! G3 h$ W) D4 @0 h, w7 V2 j - string user = context.QueryString["user"].ToString();
" l. H/ P9 j) F6 T - ! e, Y' }8 x+ ?# L" e
- try
6 w! f9 T0 i8 x! t9 a - {) O3 _& w* k, y
- #region 用户添加连接池
7 D$ q- Y" S4 H8 h - //第一次open时,添加到连接池中
4 I' T8 D }# H8 T8 n. U - if (!CONNECT_POOL.ContainsKey(user))
6 d. Q, u) N3 V. \& ] - CONNECT_POOL.Add(user, socket);//不存在,添加6 ^9 J8 ?: x+ `$ k( k7 a
- else1 `: k+ g, G% ?
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
4 _* u. E2 c" j" C1 b5 P - CONNECT_POOL[user] = socket;0 P/ H8 ^2 w+ M3 | G8 v
- #endregion
5 y8 Z: r1 Y, T* Q) M: G3 H- k
4 v9 W. N' f8 E" b! E% n# ]( ]3 \- #region 离线消息处理& H6 J: c- D: J9 q9 ?
- if (MESSAGE_POOL.ContainsKey(user))3 C5 z `- B) \- X; H& }4 f
- {9 {) n& w' K1 _ w
- List<MessageInfo> msgs = MESSAGE_POOL[user];
1 q& Y7 ]$ n: K; |# ]+ e - foreach (MessageInfo item in msgs)7 a# O/ W9 ]+ r, n4 i" A' j
- {
6 b3 u/ B$ L4 c - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
, |/ i" ~+ B# n# I6 @ - }
3 k- ?- a" ^8 E# ?! q) a - MESSAGE_POOL.Remove(user);//移除离线消息
- V# |( Z6 h- ?2 ]: V7 h% u - }0 i& V3 W2 ]) G7 f, ^# q
- #endregion
( P4 a3 ~& I! R, U
5 s6 g" A9 r$ x% C- string descUser = string.Empty;//目的用户2 T8 ^+ \; G% j3 j: e
- while (true)' q* I h# _8 P
- {
. e. O/ g: I6 f. t2 ^1 O - if (socket.State == WebSocketState.Open)
/ \3 F$ @- u) w - {
8 s4 N7 v5 H' u9 i/ J( I, [ - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);) o7 X: p% u( p N5 R- B* P5 ` a
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);8 ^4 t) H0 k) I6 O2 a4 k8 i
- * D% d2 M" o* U- F% b& X! }
- #region 消息处理(字符截取、消息转发)
0 |9 A: ^- l, N1 B) ?8 @) ?% E9 X - try
$ I$ ]/ l* Z2 V/ Y% l0 [ - {
' Y3 ^" C% l. B0 a - #region 关闭Socket处理,删除连接池: M* o1 ^6 e7 A& l
- if (socket.State != WebSocketState.Open)//连接关闭
7 l" i+ \3 k/ n0 k- F% d - {7 b' }4 |% H) |& \
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池& _9 G t8 G$ |& p8 N8 ?( G5 u2 o( A
- break;
' E9 L/ o: ^; V. c4 ]5 i9 j9 z0 x - }' D! l* L4 Y8 P% I: F. Q
- #endregion' q: S7 o) v' _" |. J4 U4 M
6 [# _8 | H, D& r6 o- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息% z/ Y+ p, K" ~3 R M, `3 v
- string[] msgList = userMsg.Split('|');/ d) }; D) @1 U6 u9 e
- if (msgList.Length == 2)
5 s0 c4 L8 m9 ?; H7 N- B3 R - {2 W9 {& B( J5 l. ]
- if (msgList[0].Trim().Length > 0)+ Q- q* r1 S/ c: G. a4 L0 Y( A
- descUser = msgList[0].Trim();//记录消息目的用户
$ U' @4 B ?! O- I: [ - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));- o+ V. C; H4 N2 I$ U% i+ z
- }
& L2 m) L) e* I7 b0 v$ D) u7 q) g3 H - else
* C2 g$ i) p4 R# S6 b - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));. A6 P' h2 Z/ x% P, @* K: ?
, Y0 O4 F3 R$ d* Y% V. M: n# h- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
4 z% I. y7 h4 l8 g' Z - {$ f7 U$ R' w) S& W! o4 ^8 Y* J
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端$ G1 U' s+ ?, N/ Z4 X. a8 w8 @
- if (destSocket != null && destSocket.State == WebSocketState.Open)
, ~1 N, b K! J& K - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
$ b! e1 b' D- A - }
3 I( ~0 D ]5 L: v% T - else
% ~/ p4 N- N: r# V' f: x - {
; {" F! m7 o( b5 W% X2 B% Y - Task.Run(() =>9 [2 x3 ~7 b# h
- {
) L( Q) a, o, g) `# {' P( K - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
- R' h. |3 s- S0 m6 N' z - MESSAGE_POOL.Add(descUser, new List<MessageInfo>()); z/ Q& C( y/ D% f- C
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息. y5 p- v8 x3 q5 I# W, w
- });+ _2 m) h) q) r+ I- r* g5 r* U
- }* Z t2 i! F8 s% A" n( O/ D7 O
- }
; } `( V& x) ]9 t& F - catch (Exception exs)
' \4 y9 m& H# I( ^: Z$ v - {& Q4 z% i% t, ~5 {' L; s* q. R9 R
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息3 H' M2 w" K1 j! {( n6 `0 W- E8 {+ k
- }1 A; e3 o+ M: P0 O
- #endregion3 R5 E6 H; ?* @' K/ A) x6 n
- }8 i$ v6 j( H+ L7 {0 T
- else% D( C: s( | @$ W5 K5 D2 g
- {1 _" ]6 L( W0 @( y3 c8 x
- break;
: D' G" Y( z" k- | - }2 d! h6 @" Q8 g& R; ~5 h
- }//while end
5 G9 b/ [8 b$ K3 G; b - }( E9 t3 A0 c- Q: i* b: d! c; V0 k
- catch (Exception ex)
2 m+ l. P: u) Z1 Z% D* R - {
9 X! `3 t4 n' h9 p) w+ ` - //整体异常处理0 N; Z# N( @4 ?# g
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
) [5 g7 C: g5 s z - }; a- n5 ~) e0 @$ X/ r' d ]
- }
$ `: ?$ s8 r( C! a - 8 u% n, F0 J. k/ k) N/ K4 w
- ' M: w* N( p6 J4 {
- public bool IsReusable
' H4 A1 W" K t3 q% ] - {
0 D) l* A8 Y! X/ l6 ] - get3 P# X, A: t' g" t( H) M
- {
* r5 a* I K& [+ y( M - return false;; Z0 d2 i1 u9 [/ m. b) x
- }2 C1 c. P# w I- }' u
- }# `9 ]/ H+ x8 b$ v7 j5 ]) Q
- }
1 c9 q9 g, f2 H+ O4 q - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 # S( B' H6 J; I o' Y& |
|