|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
# m$ K4 l1 B& i* L4 z2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
: x/ _" i+ {- Y - using System.Collections.Generic;6 X, N* d0 M" X, F! B1 o7 O
- using System.Linq;2 y5 J9 }% I- J6 ?* y4 d
- using System.Net.WebSockets;" d/ S- O: [$ e, O$ V+ d
- using System.Text;
) f y" A' D# o$ I7 C - using System.Threading;7 p+ i5 X$ o, I7 H( ]
- using System.Threading.Tasks;
7 J; W& O. l- n5 p; J( y - using System.Web;) }: A3 y2 E) l# {7 l( w7 d z
- using System.Web.WebSockets;
5 B- ~+ o- [7 _9 P - 5 Q0 j2 r' c( t, K% h
q9 ?9 x5 u9 } j& J- namespace WebApplicationWebsocketHandler
i; D' y, S; F+ A( f - {$ }7 G7 f0 u! {, ]9 O3 M2 i
- /// <summary>3 D* v/ c; X2 E" o R4 h
- /// 离线消息$ Z5 f6 C9 ?! J5 F( Q) X7 L+ W
- /// </summary>
. Z9 ]$ n4 J$ O8 U - public class MessageInfo
# x5 `2 _: j3 s g1 Q - {
) {0 q+ f) H- h% \6 u( i3 e - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
/ b! z3 P& z9 J( h7 H - {4 K% F# g. T. s1 C) u
- MsgTime = _MsgTime;
+ M3 C1 P q( O6 p6 c - MsgContent = _MsgContent;
6 ~0 \1 e9 k( J7 j - }2 D7 k; o6 p# x( B) x: I
- public DateTime MsgTime { get; set; }
& J: H" @4 Y. b' t# Q2 Q: z - public ArraySegment<byte> MsgContent { get; set; }
. z$ L: |0 S: a+ u - }
' @ W2 }6 o/ F, o: L
0 `8 o' j& D- w* ?8 N
2 K8 d* t) \- Q3 H, \* J- + M+ g! @: X' i2 b% f, W3 W& v
- 3 [. j! v- }! r( U: J
- /// <summary>, n& E n1 y$ ?$ L; A
- /// Handler1 的摘要说明
; f4 c$ K3 ?/ Y( b6 q* O, K7 U - /// </summary>
; _; {# ?2 y# Z; ~+ o+ F - public class Handler1 : IHttpHandler
: z% m* ]& }: [' p4 n2 I - {
7 U1 W. g: x, _* o) ^% v - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
! u' p8 d" F- c - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池. B6 f! [% B, `7 ^ n( ^, o4 F
- public void ProcessRequest(HttpContext context)
6 L/ P2 Z/ Z, g; ]# J! Z% ]' C - {3 J* v% S7 ]. w+ Z' b0 r
- //context.Response.ContentType = "text/plain";1 u' h% v( ?& `
- //context.Response.Write("Hello World");
/ d+ O* {2 {& r+ T) h1 }. d - if (context.IsWebSocketRequest)
9 w/ C4 V- o# L: G2 k! T: I" ] - {
" a9 }& t! v* C - context.AcceptWebSocketRequest(ProcessChat);
$ @6 I' j& `' P - } / C* n% D2 L) F1 h- Q* U2 A
- }
5 l8 H2 l% K9 t& [* T2 R - . U# t: n& z/ ~2 c
- private async Task ProcessChat(AspNetWebSocketContext context)& s5 M4 V5 x! g
- {
( w# K6 ^( D! U2 `' y0 P8 M3 X1 ?( N - WebSocket socket = context.WebSocket;! }* I9 X" r) R) z
- string user = context.QueryString["user"].ToString();
$ }# \5 P' ^2 _6 F; c
6 K2 s4 d: \& D4 g0 T+ G: ^- try P i+ }, m. `. Q: G) v
- {1 ~' B1 Y8 h2 K' j/ K/ B8 e4 l) a
- #region 用户添加连接池( M% d! a" L4 g* ?
- //第一次open时,添加到连接池中
2 s- l2 C! ^- k2 N - if (!CONNECT_POOL.ContainsKey(user)), z3 l8 j/ E8 \$ J8 F- t
- CONNECT_POOL.Add(user, socket);//不存在,添加2 F9 W1 r; e! W d
- else P/ m. k* Y+ e2 `; F8 ?7 {
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
2 e0 R+ M. I: B7 N - CONNECT_POOL[user] = socket;! I; h. q* u; u9 o. b; l p5 g( |
- #endregion
& }7 _( ?8 P5 L& u7 q
- u8 i$ [/ Y/ Y+ D" G- #region 离线消息处理2 x; F6 r# @6 r( M
- if (MESSAGE_POOL.ContainsKey(user))% n4 N/ Q. d4 \8 u3 F
- {
) u- k) J9 z: S - List<MessageInfo> msgs = MESSAGE_POOL[user]; a# E3 Q7 S# b: _# V/ s* Z( H
- foreach (MessageInfo item in msgs)
7 [6 D$ k% l4 y - {9 @* q+ v% U4 d3 R4 F
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
7 [0 F0 M8 W7 X1 f+ e - }
! i3 }8 ^. w+ }) V+ ~: C) p; O - MESSAGE_POOL.Remove(user);//移除离线消息
6 Y" A! z, f; a - }! d0 N x; f- ]1 O- i, \) }( a
- #endregion
1 a% p, _. K7 O$ M
5 I2 I4 A ]6 _/ c2 S1 `5 ^+ S' @- string descUser = string.Empty;//目的用户' L6 [$ R% g0 {0 L# o1 G* ~4 ^3 }+ o
- while (true)
z' W, }+ o" }. @! ?5 b4 `. U - {! e. B6 i1 e, F O `
- if (socket.State == WebSocketState.Open)
0 V3 D+ U9 `5 |3 p& ^9 D - {
0 ^: H& I2 ~1 e# m - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
! {+ v; s% S0 T. N) ?2 u) R* n - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);2 L1 Y" s* E& v$ {2 d; q. Q2 \
- : t/ A# W7 ~# N4 L' d9 {/ o
- #region 消息处理(字符截取、消息转发)
! T& M! W5 j, j# H) C1 r - try4 f- M* R9 ]0 r
- {* I+ B" [6 A3 I- I5 \
- #region 关闭Socket处理,删除连接池
: R( o. \" H7 o$ L; H9 B0 V. I - if (socket.State != WebSocketState.Open)//连接关闭6 n8 `+ P# `( S0 R8 n' C
- {3 f; u* N" B8 ~. I
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池: B) L+ k/ v' C
- break;" ~& h C1 j+ r# S- k7 U4 x2 x! q
- }
1 Y) n% N y0 `. {5 w - #endregion
) g9 v% V/ `* ] - / z% S* ]. e3 }
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
) W) J b+ y( C& N - string[] msgList = userMsg.Split('|');
1 h6 Y6 M8 P/ v T" J c/ ?1 n n; B - if (msgList.Length == 2), S/ B- z( V3 U' b, h( ~2 n
- {' k0 v$ b+ d7 C6 Z' E- Y
- if (msgList[0].Trim().Length > 0)8 q2 n$ H: d. X% L0 @1 i( v
- descUser = msgList[0].Trim();//记录消息目的用户# [2 L0 @9 v, {+ E% Z& W
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
) U8 s2 n. v P% B5 ?$ B - }
$ k: [) @9 t; D9 {, J - else( I% q# Z7 B+ m/ ?2 E. ]
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
: e0 }& w2 G* E: h. ^) O p8 p( U
7 ?( V/ I J; J# J- C: [' w- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线7 D8 [9 J. J# Z& x
- {2 W3 I2 r O7 g8 R
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
* K0 g. k, X, z* n' t; Y2 Y - if (destSocket != null && destSocket.State == WebSocketState.Open)
. X4 s- _5 `7 }/ G$ V8 }' y c - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
% z: F# E2 ?% C) l - }
9 D* T7 q4 Z. I9 M8 N) ]7 e - else1 t& r4 U. X7 P- C& p/ P& ?! Y$ N
- {7 O2 W/ F1 Y3 I1 M0 x5 z8 K
- Task.Run(() =>
& R: D' n9 X, ~: a4 [& a3 O - {2 _2 |# N# [6 f7 v
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中5 X5 g* A0 X! ]5 R+ P
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
1 u* d9 g2 a6 S/ Q( @+ F - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息9 k B5 }2 [$ H: S- D
- });
' q" O" ^$ |' d& J- u5 }. ]# e/ `# Q - }+ l& u* h" y& N' C- e7 d/ Q& u: ]
- }7 Y2 P" C+ ?9 p& {1 W6 u9 c% `* F
- catch (Exception exs)8 f/ u8 F: q' g' E: `% j: {
- {
& P: J! s5 _/ L - //消息转发异常处理,本次消息忽略 继续监听接下来的消息1 g& i( N+ ]+ b8 ]9 {% r a3 a/ H
- }
9 P5 n$ b) ]" @/ d2 F - #endregion9 e% V5 N% ^2 R0 j
- }
4 }& M3 d5 d; ~" J$ V3 o - else l( j. r B" ]7 b' x7 {: R- p
- {" {# J9 n- r7 g1 p8 |* g' U
- break;
' Z, q U, c4 k+ R$ m) {7 A. _7 h - }
, q* h0 i5 J! H% C+ J. w - }//while end
" C3 s" f& C2 z2 h - }
3 G8 c( B( E8 O* U - catch (Exception ex) M* W0 `) o- Z6 v+ o
- {" `" [1 T% T; T+ x1 n& w+ d
- //整体异常处理
& b2 z/ [2 a0 U) U5 P - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);$ h( ]8 |( w n/ O3 R- s* _, z& S
- }: s4 v* B$ x/ i. _4 R
- }
6 t& {6 s" j2 a G! K ]3 g: O6 H- \
, V: | B: [& S9 i4 I: q- ) O6 e$ X9 |5 R4 l- B1 w
- public bool IsReusable
F" r( e0 d( g' Q9 D' ]! t* z - {. ]% n% N% s4 P( Y
- get
. u+ t# n7 U; `5 p/ Q& m - {
7 F# }/ d$ ]) t3 k5 e+ ^ - return false;. ]7 L2 i: G3 k4 S
- }8 n/ Y$ s% q. r1 V$ X8 H6 X
- }8 h: e/ g: n$ e" h: U$ f
- }
+ K8 `) M8 w* z% j( \' Q: c - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
: m5 }6 N- l1 }5 p |