|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
, J6 Z1 p0 `0 B& A e" H1 G2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
/ [4 Y" i0 C* `8 f) G - using System.Collections.Generic;
& _ U# E# p- b; x8 w2 N - using System.Linq;
( D7 L( _" P. `6 W- }- T. } - using System.Net.WebSockets;
+ @& B- i& o4 O2 Y2 R3 r1 h - using System.Text;
7 P4 y/ y7 O( C/ a4 E+ h# l4 f - using System.Threading;
) t; A c3 F* m! X9 J- B - using System.Threading.Tasks;
* D3 ^! b1 C5 d' v$ B* B; Z' p - using System.Web;6 o2 E* L! [' Y- V% E. k# r
- using System.Web.WebSockets;1 v1 Q' O% }3 }
: E+ b5 K4 V; F4 H9 ]. v# E7 ^9 b- 1 H) J( s! o' t( b' q
- namespace WebApplicationWebsocketHandler0 h. w7 x7 I5 w( f1 @3 ]# d, p
- {
9 E2 C) c& V6 v, J6 C; Q! z5 Y - /// <summary>, b' s: h& y7 N! w# q
- /// 离线消息7 I' ?1 i. l4 E" R7 U: E
- /// </summary>
' J: f3 E1 Q4 C$ _: H# `. o - public class MessageInfo
; A6 R8 q l5 B8 e - {
* t& f/ U# p2 n- f - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)* z& y) X; o- ~+ P
- {
+ [8 O0 ?+ `4 `; m$ p - MsgTime = _MsgTime;
3 z$ z, |, ^8 ` - MsgContent = _MsgContent;
5 u$ d2 a! Y' H - } [6 r' ~$ L) A3 N
- public DateTime MsgTime { get; set; }
( M" c4 ^7 G) L* E/ @ - public ArraySegment<byte> MsgContent { get; set; }/ W9 T6 k' y% K6 |3 E M0 G
- }' K: F- x+ ~2 F* D
$ j* N/ A3 j8 z: s6 X' c, F- / i4 D% o# h) I4 K
1 |* [7 L8 Y9 |4 z- ; `8 {+ @& m3 B9 w
- /// <summary>
2 c$ T1 p! e3 x* H9 ?6 w - /// Handler1 的摘要说明( \8 N/ {8 y r: G5 B
- /// </summary> j# d6 k1 Z3 f l- u
- public class Handler1 : IHttpHandler$ C7 P. c) ~; q
- {
- A6 V* H. b+ W* _6 ^# _/ k - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
" U& l( Y% L+ K+ l/ Z - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
$ o) M# A4 A" a - public void ProcessRequest(HttpContext context): i, }1 ^3 S Z6 E* m3 q" D
- {8 w. Q3 t# r5 ?: q, W! m
- //context.Response.ContentType = "text/plain";+ ?# u3 m# e' ]5 e
- //context.Response.Write("Hello World");# _5 G% |- j! v3 ?
- if (context.IsWebSocketRequest)
8 d, J4 u9 T: z( V r0 J) `0 Z - {( E* M2 i( X5 v% U. Q
- context.AcceptWebSocketRequest(ProcessChat);2 T9 t8 E6 t) Q5 O
- }
! {6 S1 c3 b. T6 j8 }' u _ - }
7 m# {# ^5 j3 K8 }
+ Q; m6 Y$ B: q+ @) _- private async Task ProcessChat(AspNetWebSocketContext context)
" h, j3 |4 L0 j- n: E2 M7 M - {
" }7 T4 Z% x+ H* o% p2 W# ^ - WebSocket socket = context.WebSocket;
& w' O3 I6 x: ^! n - string user = context.QueryString["user"].ToString();
8 Y; ]" Q% D P1 n( O - , U2 J( w( {* ]- M( C1 n" R
- try
5 q1 ~' [3 v6 ]8 h+ Q1 { - {
' x- D; z1 P- \1 q3 G - #region 用户添加连接池% ]& v* k( U! @, r* I
- //第一次open时,添加到连接池中# S* D; ]: E0 ?7 F R9 ?% L
- if (!CONNECT_POOL.ContainsKey(user))( M: \, Z: ~! k4 K
- CONNECT_POOL.Add(user, socket);//不存在,添加$ d2 f r* K' v# T+ c" x1 i. c& N: y* i
- else
5 V3 n" d3 E6 J$ N! k8 C$ N; w2 D - if (socket != CONNECT_POOL[user])//当前对象不一致,更新 w. I! u$ F0 m2 L# G" n3 D
- CONNECT_POOL[user] = socket;1 m" G# C) s4 f3 f7 U1 R% Z; G
- #endregion* F. h3 f; \4 k
6 c- }; V9 k ?. C0 Q7 r- #region 离线消息处理) P4 U: K0 e1 Z7 b% ?9 k' Y+ y- }! M8 H( I
- if (MESSAGE_POOL.ContainsKey(user))) v! a" R: |( U; O( B
- {# d3 _/ @# w: P/ }' q- A4 ^ @! N
- List<MessageInfo> msgs = MESSAGE_POOL[user];
2 I+ }$ c# |0 S$ ^: r - foreach (MessageInfo item in msgs)
, k5 L7 O# J, u& i( s" [/ X - {7 ^7 q* @/ w4 Z" q
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
. R) k6 Q+ ]; x L6 i, P+ Z3 Y - }2 M3 w& j3 a' p
- MESSAGE_POOL.Remove(user);//移除离线消息. Y8 B' x; i- S' V1 ]4 d+ P
- }
" L" ~& [$ ^$ X3 T! T( B5 N0 W, } - #endregion2 l5 {- ~. ^% e$ B; O6 V# o+ y& Q' l' a
`+ s( p# Z. K7 x) z% |6 f1 \- string descUser = string.Empty;//目的用户7 _2 n. [; W$ w0 S6 |
- while (true)* ]! E4 B8 ^( [! M7 w$ K4 Z( ?
- {$ X7 \6 e8 J1 E: ?- B9 u
- if (socket.State == WebSocketState.Open)9 t" x$ U+ ^* Y! w2 Y
- {7 l; i& ^1 A! L& M' C1 T
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
- Z; W7 U$ T/ @: T4 ]/ Y - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
- k! {' c% _ R7 k9 q w2 ~
: i% X, H5 J a4 a- #region 消息处理(字符截取、消息转发)
4 _, c& n! U, Y" n - try' z1 a, K& a- w+ r0 k& U ]& h
- {
+ T+ n9 {& s# e# [ - #region 关闭Socket处理,删除连接池' e; G, z9 F- l' [. {; w1 h
- if (socket.State != WebSocketState.Open)//连接关闭
8 Y5 k3 {' O: Z* C - {8 s; L; }* z) [/ q- e
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
8 V" F" L& L' g1 M: \& T - break;
: s) F- L2 L6 K: x - }- W; m& t& S: z# ~/ A2 x+ G
- #endregion
/ Y6 z; l t, Z - - Z% H, F( j3 t! F+ r7 x
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
% R3 p4 S9 z/ O9 }* [ - string[] msgList = userMsg.Split('|');8 E _- E$ y5 e* B
- if (msgList.Length == 2)" o4 `3 G! `4 C# [
- {
8 D! M# ~& ^. J9 }* O4 J* k - if (msgList[0].Trim().Length > 0)
1 p m7 H* I: B0 n: _ - descUser = msgList[0].Trim();//记录消息目的用户! M. r: z1 p$ j+ ^
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));# ^; ?6 w' g+ q4 y! {: _# E# Q7 r7 v
- }
9 W0 p1 B0 t( o& a5 Q- g) `- P: ^ - else9 d4 V8 a$ p8 a# a' ~/ f1 j' C$ z
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));/ p7 d) a$ i0 w( R
; W) B: |" Z: b0 g4 U D- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
3 n4 W9 Q5 g- c# E& w - {" [1 \) h, l, K' ~5 G
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端( ^$ A- J+ ^! O6 B. ?! E
- if (destSocket != null && destSocket.State == WebSocketState.Open)
0 t1 Z6 w; |' T7 V - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);5 h2 N4 @- l( f" H/ t( t# i/ t4 m
- }8 e1 W# c" T) Q! o+ Q
- else! ]: W2 b3 N' f8 ^; H9 s
- {6 `0 E+ r5 @1 H0 l, }6 {3 V, z
- Task.Run(() =>8 [# Q' o; f4 Z+ b' q& n. Z- j
- {
% F) Q# u* D# \" C" F7 O9 {2 q% ~ - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
z& U# z4 x% W5 k2 x6 z6 d - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
& c$ [) [2 p- R# J6 v2 n - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
6 f+ q) `' p, t, i9 g" i - });
1 m5 O8 c% K' M5 m - }; }* W. l; r. b1 x" u
- }- m7 I4 r) t' E- z1 R8 m- K( Z
- catch (Exception exs)
) ~" V5 k+ K: N! l6 E - {
1 f* O' _5 f' e+ V" h+ S H3 C - //消息转发异常处理,本次消息忽略 继续监听接下来的消息& _+ e h" i/ g
- }
, Z/ u0 y: f: x& Y - #endregion
) ]4 T8 J. u" g: N' x6 a& W - }
: \( r* I5 D; w/ I$ E) i& s) T5 _ - else! A# H9 G0 b/ U8 j7 R6 r
- {
o/ a. {+ n5 E; w - break;
2 O! K3 z" j% l8 T+ V* S# r& n - }
5 _; [3 ~( F3 C - }//while end
3 ?$ V1 W2 Z8 X - }
! G1 u* i) ?2 S! k( d - catch (Exception ex)- ]' c- K' I( Y/ ^) p9 o2 o+ Q$ B
- {
/ H) U! Z: E0 i - //整体异常处理
( f/ f7 } F& T" P) J7 C% K - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);" O) j- o7 R* d6 f) w: b4 Z2 G
- }
7 E2 k$ T8 E0 }( I3 k6 U- b( V; o - }# w; k$ t+ ]) s4 G6 G/ a7 c
- . r( q" r+ }3 [8 |
- ; X5 N( P$ Z$ M% q% q/ F% K
- public bool IsReusable( E. q0 |# T5 M1 p7 t% h, a( Y
- {: D* S, q* K0 O* z) A9 i+ {
- get5 C0 |* C6 C- d) z$ s
- {
: { C6 V9 [% Q: G% z - return false;: J$ U3 m# @: F
- }) N$ k: J( Q; R. @) n
- }
8 G! f# h& b$ y* [% i, { - }
& w( @5 N0 X8 o7 e+ J& v - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
- c n% k$ R0 a) I0 r |