|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
8 h7 o5 R1 E3 c9 n2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
; y# \7 g& e. ]: j2 p - using System.Collections.Generic; Y$ `/ G, k8 }( Z, [" m G( H% H! Z
- using System.Linq;
% H& U8 o) J5 E$ f- s3 k ~' L - using System.Net.WebSockets;' U5 N1 C5 C2 C7 B- `7 S* W. ^
- using System.Text;# o. x1 [: d$ Y5 p k! K
- using System.Threading;
6 w' R7 }5 k6 w1 Y' Y; L; G/ { - using System.Threading.Tasks;# d6 c" p9 d0 D1 Z
- using System.Web;' {$ o" c7 b1 b- v; A M& y' }$ d$ [
- using System.Web.WebSockets;8 e8 a& o7 j( U
+ [* T( H& d; S6 f4 l' J- 0 W" S/ ]0 s ~2 d& m5 X: N: x0 n
- namespace WebApplicationWebsocketHandler
. x$ n8 r5 _, x" k( K - {! ~: _8 k! L4 B
- /// <summary>0 h8 u( w- O( y9 i
- /// 离线消息 P- q4 N. j( `1 S
- /// </summary>
7 e; [- u; B/ Y( {' |+ ? - public class MessageInfo" J1 H1 H) F1 x' K! @ ^
- {
; H: p, C7 H% X M( m - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)/ ]6 h/ b4 l' k9 R$ v) c1 f
- {
2 W4 P3 ~; H( g4 g - MsgTime = _MsgTime;
' F4 t/ Y6 n5 z+ y6 g+ d - MsgContent = _MsgContent;# ?/ o" @$ ~1 j7 @2 E
- }
8 }! X5 C' v8 }: Z9 o - public DateTime MsgTime { get; set; }7 Q! v. j5 k. |' @' _7 F9 n `
- public ArraySegment<byte> MsgContent { get; set; }
4 R$ @- T! B( G; j5 ~ - }" z' `9 d* u) n4 T0 }* q
- 2 w r3 L! J* Z
- & |' Y9 q2 B( ?0 _: j8 z. ~
! p+ |7 G8 i2 f, m! a
( {/ H1 `+ M8 S0 k- /// <summary>
7 | h7 H1 C: t6 p; V1 l - /// Handler1 的摘要说明, V3 C/ i. d' n4 A+ q7 U0 g% y
- /// </summary>
. D& H, J" \! [- I, G- e - public class Handler1 : IHttpHandler' Z7 Y- {& ^! Y) r9 l0 d3 e
- {' ^) N' `! f8 X: L/ W. N8 F. ~
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池 _0 M; K8 z& ]1 w7 ~) z3 d5 y
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池% A0 t$ y* J* w, q
- public void ProcessRequest(HttpContext context)* i' x4 ?8 g/ ~% V6 S7 C: {4 O
- {
5 |: G8 L8 z6 c- X7 o - //context.Response.ContentType = "text/plain";# m0 f4 Q1 u- u1 w3 c' [) K, l
- //context.Response.Write("Hello World");
3 J- v$ W+ O4 N; b; }+ u+ I( g; l - if (context.IsWebSocketRequest)1 L# y& f( c# y# o# C$ g1 V
- {
3 b6 M2 T' b- e% Z9 d6 S- H% R - context.AcceptWebSocketRequest(ProcessChat);
: A3 X7 e" x3 S& ~- R& O% C" ~. b# S; J% [ - }
' V. `9 E& V0 V) [7 u - }
; }# k2 b0 L6 p! p6 v V
8 V4 a% R+ R4 c5 o% ]- private async Task ProcessChat(AspNetWebSocketContext context)
1 g7 o8 f7 y S L- `; {" ? - {
- s4 G# U7 [0 U* o! {; |+ } - WebSocket socket = context.WebSocket;) p& P7 I$ U& t) Y4 f! P
- string user = context.QueryString["user"].ToString();. W9 I! Y' f6 N9 u
- 8 q2 I: g$ e) H3 y1 o) O0 _
- try* e+ K4 W% b! P0 K( e# b% _/ s
- {- N/ j6 E/ x' v a
- #region 用户添加连接池
; ?% F7 J* i" W( s% B; n/ o - //第一次open时,添加到连接池中
8 x! H6 X d5 K& s# Y h - if (!CONNECT_POOL.ContainsKey(user))
0 @) {4 V4 Z" i! y; a7 M - CONNECT_POOL.Add(user, socket);//不存在,添加* j% g8 J4 t. b( U ]+ w$ g8 U
- else( w0 e$ U% H. X& D
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
% M% R8 P' E9 v- g5 D( Z! D. u - CONNECT_POOL[user] = socket;# A* y4 f% h; @; E* i! ^
- #endregion
$ Z! ^. x: c) a5 P
$ `3 d& z5 A+ j- z- #region 离线消息处理7 q% \# O" b; M+ F5 c* J2 [$ a- f
- if (MESSAGE_POOL.ContainsKey(user))
" y1 u) _9 X$ L, y+ n8 ?7 N - {5 ?8 f( V5 [/ |# X3 y" l7 _
- List<MessageInfo> msgs = MESSAGE_POOL[user];, Q7 Y) w5 s9 `4 R
- foreach (MessageInfo item in msgs)
+ a# v8 w" f \9 Q - {
1 U, U. ?* A+ }8 d" u - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);: q# M7 I0 E' k8 \
- }: L1 ~) q# n1 L" l
- MESSAGE_POOL.Remove(user);//移除离线消息
: ?, G- y) K" r5 a- h7 U - } J* {( @4 I4 s8 D& f
- #endregion1 A9 \& h( {7 k4 ?* D( P
3 f* o! z, H; ^. E( D: ^9 F- string descUser = string.Empty;//目的用户9 |6 w. J) v" K
- while (true)$ B' S e9 [$ I% K/ e/ i- N
- {5 ~6 x# W5 i) @0 C( f' u: b
- if (socket.State == WebSocketState.Open)
$ b! X2 i8 O) H0 D0 R$ {- v - {
5 D+ \8 i4 L# n8 e A" O - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);+ o& y* {5 I! Z$ Y
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
6 E4 R; d# e% v+ N0 m - c" F/ H5 x1 x6 o0 l
- #region 消息处理(字符截取、消息转发)
8 V1 K1 H6 y0 u$ t2 F - try" d7 m# p: `1 f/ {' ]& K
- {
; U" w3 B8 A g) j- g0 x' s - #region 关闭Socket处理,删除连接池
+ f- T8 a9 j& D! P! ` - if (socket.State != WebSocketState.Open)//连接关闭
: v# O$ j3 g* L+ g0 z9 g - {
; C/ ~- k6 M7 ]9 B2 L6 Z% k - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池8 w0 c- t4 @# z% `7 u
- break;
3 B' U0 q0 D# S- g9 m - }
6 f0 ?" g y% n* G# \- K - #endregion
4 l; Z/ m* P5 S
; d1 u3 M" Z @+ R0 c/ B6 p$ [+ O- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息3 K1 B" I" q% |8 M `! Z4 |
- string[] msgList = userMsg.Split('|');
' S4 v. v/ }& ~% v) F" i8 `; A - if (msgList.Length == 2)
1 l. K! G0 k' f9 y1 B- `2 r - {; F3 o4 G; W$ W* \
- if (msgList[0].Trim().Length > 0), Y8 O. q# z& e' D
- descUser = msgList[0].Trim();//记录消息目的用户
" @ A9 A6 w0 ^# M e% y; l% i6 ` - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
; g$ E$ G. ?+ w: ? - }+ `: w# J) Y* v8 v9 [) P
- else( E. n% k, p5 F7 i" [6 h
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
' a5 ~' P2 e# t1 R/ k# P! N8 Z
* y. N0 R) }1 a- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线$ C7 c% ^/ d& l, H f, n
- {3 w: w* y- H& V9 W" Z! n4 Q
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
3 |7 l* U! ^* }& c/ `' G5 k+ P - if (destSocket != null && destSocket.State == WebSocketState.Open)6 W2 S, y- U0 s( s! M2 H4 p
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);( L7 P: r+ w8 }% `0 x) s& Y
- }* y, D) g1 J+ G' d$ X. a9 l' E" r
- else
* u+ d7 O: B. n: p( X - {" n! K% K4 C0 _
- Task.Run(() =>
: N6 [$ r/ x! ?8 ?: h' c - {
' j1 ]) @! Z z# N - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中4 F* i/ F% d% b) I
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
) a# b: A: K3 K6 D/ f4 c - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息' k0 z @1 H: c6 a$ k1 j1 A
- });0 k: d% I* r5 V! Y' q+ P
- }
% u+ H9 R# m G: ]5 j0 s& D+ u - }
# W4 i, E3 S9 Z. J9 X4 W g - catch (Exception exs)" V7 d* a- V- x" Q# X7 J
- {
8 E- N }3 ]6 Z5 ]( p3 w, { - //消息转发异常处理,本次消息忽略 继续监听接下来的消息; r1 g! W/ _* N' k8 A
- }
1 m1 Y( i- W8 V, W+ J, F - #endregion
# J6 W& e9 ^% Q' @ ~ - }" u2 R9 h: h* u ]0 P+ z
- else
# E# h( K8 A" L, f8 m) C) Y - {
- f* t. P: h- D8 }. H2 D/ ^ _ - break;8 k) b0 z4 |5 `8 d3 H+ Q4 H
- }
% x' `- g9 f* }1 y a( P5 p9 q - }//while end
. K0 f. P& w4 k- `; j- V - }
' F- B$ ~. [* m5 z$ x `2 g: N, | - catch (Exception ex)
1 \9 D! y3 P# f+ e e4 } - {/ _8 R# b. E# {- P
- //整体异常处理% }1 J% B: D+ v5 Q/ L. d
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
j* e6 _5 g( y4 h5 M - }
8 `% J3 n1 h5 d9 i& S' C6 { - }9 L7 S4 G$ |# h) T, b
- ! g; F0 l, t3 y; P
* W3 J) u2 N! ~& n# O, Z, h- |0 J- public bool IsReusable: M: @9 N8 B6 b e, _2 Y& B2 |
- {* b: n2 f H1 p& j9 t
- get& i& B9 o, M, R# O; B4 ^/ t
- {
. y% j. b E2 F! y& N- C - return false;' D- M Q* }$ `( m1 o
- }
& W, D$ Z7 v, u" p% { - }
* M9 _8 a3 n$ h8 @% o - }$ b# x! Y, {1 a* G3 }
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 3 w' d* J7 g$ S' [/ g, g+ V
|