|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 ! \* z @! V0 K, i4 h
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
$ H2 c# u, p5 E; s - using System.Collections.Generic;
Y' K9 \+ V0 }1 _1 o! t5 q - using System.Linq;$ u% a: h7 ]4 `# y
- using System.Net.WebSockets;' a- v3 b3 ?' a# G
- using System.Text;$ S- I0 j6 c( \6 Y4 a
- using System.Threading;/ e/ w5 W7 s1 h v6 f0 x
- using System.Threading.Tasks;4 K' T' c& r; e$ q+ R0 F
- using System.Web;
/ I: K, K3 f: q3 u4 p; K/ d6 X - using System.Web.WebSockets;
# P# i6 E U: Z7 `3 Q) A
3 C' a: K8 X$ |7 j7 _" x
& r! o6 Q @* X- c/ C' J" Y' W- namespace WebApplicationWebsocketHandler% y# [2 n# T! ?1 a
- {
7 h$ K- f1 d. `* D( }# A - /// <summary>
/ L, H5 q7 t; _8 |* ^& I7 P - /// 离线消息' I9 f) W, o, t# H) C3 m6 ]9 j" Q
- /// </summary>8 o3 {2 u# H/ m: }1 Q9 Q) {6 g
- public class MessageInfo
; {& N1 Z7 P A& o) Y% w - {
6 `, ]+ ]2 U k4 g7 ?" u - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)9 o1 m- @+ Y* ~1 I4 }2 A
- {- A$ r3 [+ A. B! J
- MsgTime = _MsgTime;/ a# s& `0 s9 b8 ], M
- MsgContent = _MsgContent;- J, z, P: y4 _- S2 A4 ^
- }
* n4 ]( u. r R/ \1 H* m7 {1 P$ z' q- S - public DateTime MsgTime { get; set; }
/ A+ W$ ]9 {- |" K) [/ V! k% l - public ArraySegment<byte> MsgContent { get; set; }
: f( b; r* D' Z, N I6 V# |% H - }/ L3 J' ?" i/ ]& O/ p: O, ~
; P* D- K" S9 W- r5 p$ p- $ P/ O% M* X& U6 D
- 3 A! Z( j+ Z4 s. y/ e; Q6 X
- / c* q' U1 H+ j, W6 i7 Q! n0 ?- _
- /// <summary>
; K5 G0 e3 _- ~ - /// Handler1 的摘要说明2 [" J) B. ^1 d+ {5 Y! f/ j' H
- /// </summary>6 Z# q- O0 x5 b; b
- public class Handler1 : IHttpHandler
( c) u8 O. W' T1 n - {
J8 s0 W. Y6 c! u% } - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
! p! u8 o M( ^) C& K - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
, u0 N( y2 N6 D0 m% a _ - public void ProcessRequest(HttpContext context)& }# d7 I5 l: C& f V
- {
G$ y4 u/ i. p F! K' X" h - //context.Response.ContentType = "text/plain";3 e) v& h& T5 d$ w- |8 \$ g
- //context.Response.Write("Hello World");
' y6 C/ y2 i6 W$ j, n) n( @ - if (context.IsWebSocketRequest)
: X1 k* y7 H% Q+ @* ] - {* \ @5 y4 W7 o/ s/ h
- context.AcceptWebSocketRequest(ProcessChat);3 v5 S/ ~" q5 z( P& N7 Y
- } " j9 ~, X, K" `9 E2 r0 Y, @, g
- }
5 H) f9 n! q1 L. u
7 U' a" K7 F) o) k5 N [- private async Task ProcessChat(AspNetWebSocketContext context)
( E6 i6 R( u3 S - {+ N" P4 a9 P1 k# P5 z; N5 o
- WebSocket socket = context.WebSocket;' z8 y$ E: l7 y9 b! Q2 D* {
- string user = context.QueryString["user"].ToString();- D) L y* c% X5 T7 q6 a! e' w( V
7 q* C: k+ m8 K* I3 H- try9 J! {. \. J8 n" n1 q0 A- i
- {
- s. Y, ^0 ~% s7 T/ N - #region 用户添加连接池6 W. m, s# T% B( Y. t7 ]
- //第一次open时,添加到连接池中! B, Q) U1 q3 E. i% Y
- if (!CONNECT_POOL.ContainsKey(user))" L, k5 _9 G6 |, M9 u! \+ \
- CONNECT_POOL.Add(user, socket);//不存在,添加! O) |: U+ @% l l* i0 U0 c9 i
- else
% m0 l- W7 |* r7 a& o; V - if (socket != CONNECT_POOL[user])//当前对象不一致,更新; U8 r& [% a% k" u* E4 T/ A; n8 e
- CONNECT_POOL[user] = socket;/ q8 g9 j7 E% h
- #endregion
" w: U3 _& L' g+ n. K1 K
$ U% y, A+ x2 _/ r" C- #region 离线消息处理
4 i e3 x& n7 I- M - if (MESSAGE_POOL.ContainsKey(user))1 @/ w6 t8 _$ t# u; _+ r4 N$ @% j
- {
: i8 w) n! v, L- m; H K - List<MessageInfo> msgs = MESSAGE_POOL[user];
. d0 k0 s$ s0 o. j" W: b - foreach (MessageInfo item in msgs)' Z8 K0 d, s @1 E
- {$ V) i1 \5 n; s; Z& N- y/ q
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);3 i" E: r" F5 S. O2 ?$ _7 B
- }( `; p6 h. j. G' p
- MESSAGE_POOL.Remove(user);//移除离线消息
$ c% B( {0 t% Y! } - }& b" J( A' X. E, A! p
- #endregion3 N" H% h4 w5 u1 r8 p+ z
& B9 x0 ?% }' \) T( q- string descUser = string.Empty;//目的用户( i3 m' W- [% T9 k6 b2 R
- while (true)/ h& m0 r# M- b, M
- {
6 L) h! i7 _, |3 T: g4 V7 V - if (socket.State == WebSocketState.Open)
7 D. p8 f+ \5 y' \ - {
% s& N- V; ]! L+ E! ^ - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);+ {: d2 Y4 S' L( O) o
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
_; |: J( G4 m
, T/ u; q0 [7 Y/ w. l/ W' w- #region 消息处理(字符截取、消息转发)- c' N7 t; }6 r& D
- try
4 j+ O% v4 O: T7 \ - {
* `* S, D5 j( R+ V - #region 关闭Socket处理,删除连接池
# ~% o# I% h% Y* [, z - if (socket.State != WebSocketState.Open)//连接关闭2 z- J) k/ d# Y }4 x/ e, z
- {
- G( ]" y- Y8 _: p& s9 c - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
" M$ W0 Z9 y" J. x7 j c9 `: [* T3 R - break;
1 R9 B4 C# l% T - }4 p6 M) Y2 C" |8 s5 Y5 ^- g5 v# Z
- #endregion
U! E& K0 z( I - h6 @8 }7 X6 P7 v
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
0 c" u0 y4 t# h& R$ V - string[] msgList = userMsg.Split('|');
; N" @9 q7 {7 S! { - if (msgList.Length == 2), x% M9 n; V9 O9 @0 j% X* y- E
- {
6 r! G" E* i* _/ x" k% M - if (msgList[0].Trim().Length > 0)* ?& P" ]! h0 b
- descUser = msgList[0].Trim();//记录消息目的用户3 H, t9 ^1 N5 m$ r3 l0 a5 A
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
& O2 S3 A% O8 i - }
& A" a; e" j( E( a# j - else
6 S3 O/ D6 H& U. L# Y - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
% a- D, {0 S/ {+ }
' n4 X4 a/ q4 I9 k3 J9 U- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
) S" f, Q( U) o% q# \+ B/ U5 _' N/ D - {0 E2 \& v+ a3 T1 I; a
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端. a3 Q0 U- X* p; o5 d9 y, `
- if (destSocket != null && destSocket.State == WebSocketState.Open)+ N: ~- h( K% b/ k3 V+ F
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
2 K* V5 ~# i- @4 j# } - }3 n9 K r; x- j5 l( a
- else
, j+ q" d1 O B) M( D1 ` - {
& d. }. [! M. Q - Task.Run(() =>$ r/ t4 |2 ?5 u2 J( t0 S
- {& o% i2 y4 [! X6 E! o) C" z
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
& Q7 e8 {; ]6 k, f0 \ - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
: J1 O$ ~0 X5 C. }% K - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
! f) |5 g/ \2 O: @9 I, x - });
7 O( Z; {6 c7 {3 @ - }& { q" e2 |9 Q% i i) }+ T. Q) I
- }
7 d7 u7 r7 c1 t( s1 X - catch (Exception exs)
3 o$ M' I1 y+ O! e7 h1 z5 B - {! U9 D! a3 J& E7 E
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息1 P; o( S7 N$ i K$ u
- }9 { s! p. g" j( Z+ b
- #endregion, ]& I6 W$ e! z. {' @
- }2 W" j% n. G! ]* K; S
- else
( t. s+ Y2 d$ d8 [4 ~/ a - {
, c4 Z3 o: m) D - break;1 ?, R7 K" X/ E% e+ U
- }1 a" r* j6 ~ A7 b, \! N" Z+ j
- }//while end
& E& _0 Z E, B( C( A - }
; I; s5 I2 q! W, t5 G, { - catch (Exception ex)# z% I/ b/ v: {. ^8 o/ r
- {7 Y C; s# A8 @2 M6 q2 \1 e' d$ S
- //整体异常处理3 D* R4 ^" s- x4 w# D
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
* V2 A: I8 ^: f - }
& x5 R r! ^/ D( ^2 v o; o - }
: N/ X- K- _/ K5 c# C
- }( C" r1 k" J2 I5 C# j
. Q& E5 S! _0 M$ V _2 F0 n- public bool IsReusable
& Q ?, c& g! h) F) _- z" Q8 h$ O - {5 t" i6 n# ?) f* j
- get
# C: h+ w+ r2 ~2 y- b7 k% d( h - {0 l/ L$ t( F1 T. ~& Z7 h
- return false;( ?! L; g8 k& n3 L2 E
- }
9 F$ b. ^ N0 u7 q - }
: o1 ?1 A+ a" L1 p, t9 M - }+ S$ m9 ^/ I+ h
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 1 C6 D) t+ @) b, _$ K" V8 a/ }
|