|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 & R1 k- n% Z0 M- _$ o3 U5 `% s" c; r
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
. y2 X4 q9 e/ a$ C" Q+ Y3 J - using System.Collections.Generic;. h$ Q. f7 ~+ r4 j {. X! {" O
- using System.Linq; Y: i% L$ T: L- S0 T$ x, C: L
- using System.Net.WebSockets;
4 ]+ O- C) d; ?# n0 @6 Q4 c4 p) ? - using System.Text;. H4 x/ W4 H! }5 M
- using System.Threading;
: M" O% d# a$ Y% Q - using System.Threading.Tasks;
& k* s6 ^3 W: g7 y0 k, \3 g0 Z - using System.Web;0 S8 @& v5 i4 N, ^; L% j
- using System.Web.WebSockets;
0 c B5 e# \3 Q+ H' n% w
' r- j# f" e6 n' B" S- }5 G- Z" ?& p( u: D m% O
- namespace WebApplicationWebsocketHandler5 b% k9 ?, Z1 {% ]' E
- {
. T; q9 n K9 V0 u% \; t - /// <summary>
$ f3 V, b1 o; v' x7 K" {/ ^ - /// 离线消息
1 B: T u8 i \$ t* u4 k; j - /// </summary>4 c/ Q4 |+ M+ _5 d* L
- public class MessageInfo
% p. N0 A* |/ g, c1 X6 V6 E) A& G( L - {
8 N ^) g7 ]) h- J - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)* O/ v& X- Q7 q) a
- {: I9 O4 R) ]" D2 R1 E0 z
- MsgTime = _MsgTime;+ w+ C9 ~% i% h; _4 D
- MsgContent = _MsgContent;% g$ u/ x0 O) q9 `; x/ ^
- }
: D' W" i6 E3 v1 O/ D* w' N - public DateTime MsgTime { get; set; }
0 }9 l( B3 l# m! I- d1 b! R - public ArraySegment<byte> MsgContent { get; set; } u- G* M3 \5 V& Y$ j! _
- }
# y% I B, H" q K( w
0 @0 Y: p/ K: ~. s* p7 h* b2 u7 G
# P: s+ U7 c3 h. ~1 t, d- " R3 P! f8 ]4 [0 \
7 K; R$ z3 |/ S! c0 x# @! X- /// <summary>
8 h7 E0 Z) F* Y% p* }4 R! ~) B8 k - /// Handler1 的摘要说明
/ Y; J: N! V! y" D - /// </summary>
$ H4 O, g8 U& o6 H( W- o7 b - public class Handler1 : IHttpHandler; b5 M, U! v2 j6 l
- {0 r- n0 {3 l2 a0 R m
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
5 H; B* ?6 v1 F1 f - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
$ R; I& n0 i9 m2 N" |7 z - public void ProcessRequest(HttpContext context). b) {& {1 h7 M. n- `2 ^
- {" c4 `; S9 M5 n l, O1 I
- //context.Response.ContentType = "text/plain";. {. p) _% H9 m) f/ m5 X8 C7 T
- //context.Response.Write("Hello World");% G6 [, ]0 N6 [% @4 C3 }9 A2 P
- if (context.IsWebSocketRequest); @1 [; D1 U- F' Q c
- {
. |8 _: l, l$ D+ A/ H' L4 ~ - context.AcceptWebSocketRequest(ProcessChat);, o( t$ |7 ]- u; b/ S4 o
- } # ~& o5 W @) z; \: L
- }
: b! X: U9 p2 m. }+ H) `; `$ h - S: k7 T/ J6 H1 O( \
- private async Task ProcessChat(AspNetWebSocketContext context)
, c0 y. ^- X4 X, L* n - {0 T- j+ M4 h6 \! T" h$ x' `2 D
- WebSocket socket = context.WebSocket;1 B9 `1 Q6 s( `
- string user = context.QueryString["user"].ToString();
8 G) y" ?! G7 I7 z - # D1 I e' r+ F! V, ~ {- ?
- try
! N" ^3 U2 o0 \7 e+ h I/ Q! e - {
. [2 L* Q: ?+ R8 |! {* Z( L* d8 L - #region 用户添加连接池
* o: _" X- u& {- ?6 N - //第一次open时,添加到连接池中
3 h2 g9 |- t% S( j0 N1 s - if (!CONNECT_POOL.ContainsKey(user))$ }( I" s1 b# x2 W6 F0 i
- CONNECT_POOL.Add(user, socket);//不存在,添加1 v% j3 c1 z% @9 L: H6 j$ r4 \
- else) F/ e8 c) o4 M* X
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新9 R8 ~7 H9 z Z
- CONNECT_POOL[user] = socket;
9 T5 i* |- ]2 d' _ - #endregion0 ?; N1 r- G. g& d3 D
- 0 \! K' {4 B$ H. y
- #region 离线消息处理0 ]% t# g C/ O6 p
- if (MESSAGE_POOL.ContainsKey(user))
; ^* {$ g: H5 s2 b - {
; {. J) Y/ w2 K: Z1 q2 ? - List<MessageInfo> msgs = MESSAGE_POOL[user];
( ^# _& E( }* E8 p: s - foreach (MessageInfo item in msgs)' p. p0 i3 K5 n1 V7 u3 u
- {5 a4 R* l4 @! T+ P9 Z
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);/ e/ k3 \9 [* m! S& n$ l
- }2 C2 a: ?8 ?; J& ?. d4 t# o0 P
- MESSAGE_POOL.Remove(user);//移除离线消息
3 Y/ b: Q$ K' v7 u4 y( s - }8 S9 k$ o3 D, t6 \- Y6 B
- #endregion
5 S3 |& e, Y% ~# m, |
) R3 m4 r+ M# o F- string descUser = string.Empty;//目的用户9 |5 [3 W+ n% n3 G- q0 {- a
- while (true): ^. X5 E7 d% k
- {5 V, z3 E4 c& _
- if (socket.State == WebSocketState.Open)
, t$ d5 j9 d! z3 n1 Q - {
! f4 Y; a3 W2 J6 J- K# q - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);+ h/ {% l7 m: M$ d& Z
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
1 @4 O/ p1 y! `7 x
2 m; Z* p# J2 ^5 _, _% Z- #region 消息处理(字符截取、消息转发)
* O0 a7 r( ^8 i, ` - try( D5 G& {$ K h( J
- {6 y' m# |$ J7 {2 z
- #region 关闭Socket处理,删除连接池7 P8 o% C* D/ V9 O0 R p' U
- if (socket.State != WebSocketState.Open)//连接关闭' l6 `6 E( \1 p) J1 c" ~
- {- [2 g& \) @+ k
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
1 Y r( q* b1 p - break;
" M. ?4 d7 u. }) U - }
- C" I9 w0 E( @ - #endregion' l$ o0 D$ T2 _) c' Q6 _
- 5 W" \8 R: R5 T$ |# O9 v8 U
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息2 s4 R. F& G5 _7 W1 M8 t* c
- string[] msgList = userMsg.Split('|');' q0 @5 J1 ^9 n6 l% n: t4 z
- if (msgList.Length == 2)
. h4 ~' r6 `, @4 Y1 R2 M - {
# H8 E# [* |3 ~& d - if (msgList[0].Trim().Length > 0)2 T+ P% F# x% `% C9 s8 ~ p
- descUser = msgList[0].Trim();//记录消息目的用户7 Z, |5 g: l0 B) }5 N8 j3 [
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
0 S: J) R; a ?" k - }
; h0 q/ D4 B) ~1 I - else
, z3 r6 V9 A$ {$ P! E& Q - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
4 W, ]1 P( _6 I! `) ^* P - - H8 q( [8 W0 Z8 v' s& s1 P4 \
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
) n w2 d2 E/ o/ |, u - {1 R" v2 q# |' g
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
! O o* C8 b" d( Y9 s* y- K3 I - if (destSocket != null && destSocket.State == WebSocketState.Open)
, h8 A. c6 G! ]8 D - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
! g; j* V. p* S, w+ {$ C - }
$ Q v7 m, J( Z: g' Y$ K. C - else
0 r" }& E/ j% l% t7 S - {
2 N# }3 U/ a/ t4 X D: } - Task.Run(() =>/ n* G3 h# Y: R0 |& j2 P8 I
- {" z" I; I: s! N1 }
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中' x7 C! J! X- S3 G# ]) |
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());0 v9 ?: k5 A7 N) V8 O
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息4 k& D* C. F8 L6 w; d8 Z
- });
7 l' H6 f! Y& L2 b$ I: b8 Y6 ] - }% k& u; n3 K5 r( W1 o& F6 _$ G- k
- }
* l4 B; k* D; f; [0 c3 o5 C) q$ D# ^ - catch (Exception exs)
& q! G. _- y% j' k, d0 U - {- A r" B0 m" s/ v& n
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
$ g) n9 N. O7 j1 l' [ - }
( z0 i9 J5 S. L2 M& V9 n3 W' H% I - #endregion' `4 y+ n Y9 B1 \& t0 e) y
- }
4 i1 z6 V5 i, r) o - else
I$ q" U, z/ Z+ o: f# b: N - {: u |9 K* M' m
- break;" |6 o+ P% V" ?2 n
- }6 q6 `* L9 G0 s3 w+ o
- }//while end8 v& c$ o0 Y, |
- }
) H8 i% ^( V5 y/ _ - catch (Exception ex)
9 Y3 }7 V* H1 N3 _( j m+ ] - {
: A* `2 ?" F; X1 R5 T - //整体异常处理$ V; G: m, C# h5 b4 f; B. D
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);; P: _( \2 ?9 c& k J
- }
4 c/ E/ z$ F4 J1 M( ?0 t4 n5 c - }! K' V5 }% ]& r3 M
- e; J8 t l3 U# O+ d% ^6 I
- ' N, t* g2 W2 t; P; k4 ]
- public bool IsReusable
# f# K3 r3 U$ p& t7 K7 R2 k - {
- A- B3 S* F" c4 j; F& h! X( ` - get/ X8 Q. k( U8 t4 a) i, b3 K2 G4 b
- {0 N3 d' Y0 \* H; n8 ]! E( w+ E
- return false;
8 u7 r- f5 N* }3 o: H - }
7 J; h, O% f2 g! u: d7 ` - }
& m/ e: |$ K7 g' [; c - }& C f% v. `/ l
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
( T. B& ?% G5 t6 ]6 r& h1 b |