服务器端代码编写 1.新建一个ASP.net Web MVC5项目 9 @9 `5 q" t4 w' q1 u! ~
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System; H6 C `+ s k; m# e8 W; I
- using System.Collections.Generic;( @- d8 _" u% W9 ]* Q; H3 ]
- using System.Linq;! E( V# J& h, c7 p g
- using System.Net.WebSockets;7 \6 w0 s0 A' H9 ~
- using System.Text;+ i( V: l0 z; j$ T: M8 _
- using System.Threading;! A* o Z5 {( @0 D) Q
- using System.Threading.Tasks;
! s+ d7 F, {/ u' F9 ?0 Y - using System.Web;
" @3 B7 o) u* j9 j& v: |7 F9 t0 ] - using System.Web.WebSockets;5 b/ B% y" G! r/ M! T& y: R# Z9 x* }
. e" T" n' ]. ` F1 G% d3 f* e- ( ~+ g) j3 A; m1 d# H
- namespace WebApplicationWebsocketHandler
# b% w5 V5 [! W V* W - {0 B# r. p$ H. `, g+ A6 o+ G Z
- /// <summary># T Z6 P- {3 G3 T5 y
- /// 离线消息6 h, f) @$ F% O6 E h: L* o
- /// </summary>
/ q) w2 M7 d" d, F- a - public class MessageInfo, {, b& w! v* O; x
- {
' O* T, T M; M( Y* c - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
: n" O! l! e) W3 n, Y3 C - {9 ]: Q6 Q2 `7 n2 P: c. U0 ~
- MsgTime = _MsgTime;
2 ]7 c% G J5 O - MsgContent = _MsgContent;# U/ w6 |6 @* N k
- }
( I1 V; p+ @& \$ x2 t- u - public DateTime MsgTime { get; set; }: u5 z, Q) s1 s. v
- public ArraySegment<byte> MsgContent { get; set; }( J& }8 q x" V6 e+ H A
- }
8 T4 [/ p' b0 S* l+ h+ _/ E
9 g" B n* v2 z! O+ A P
1 a; ? Y( a- m5 n1 k9 W
1 o5 ]( k' U8 t" l- " }& p2 P6 D n' L. n# h, A. U" B8 q; w
- /// <summary>
}% q) u& P2 j* N0 V2 ] - /// Handler1 的摘要说明
- u4 v. Q& G& p - /// </summary>
0 V+ q' A! d) f: t- t$ t5 u) { - public class Handler1 : IHttpHandler- a, \/ A" _* X: J L1 e
- {! w. v! Y2 }7 j+ G) t$ [
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
j7 i* t' I. l: u9 @/ Q5 f - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池6 O3 y5 T, d4 d G! c6 A% w5 `
- public void ProcessRequest(HttpContext context)
2 k7 U" P1 H" M' I* H$ l$ s& C - {3 d# w G6 W" g; l/ u5 Q
- //context.Response.ContentType = "text/plain"; U7 l# X( C6 J3 J. U
- //context.Response.Write("Hello World");
7 U6 j; T) ^+ C! j3 l) O6 Y - if (context.IsWebSocketRequest). a* a! f) \0 \" O( W$ r+ s! Y
- {
) u% e$ n5 J* B/ i. f& v$ q0 h - context.AcceptWebSocketRequest(ProcessChat);
1 |0 ~ b! Q2 G* l - }
; ^; N8 g9 U5 \4 E; p! b+ @ - }
7 n& m9 A# a7 ?" E. i
# o, f. Y* ?- v* H( d+ M# {- private async Task ProcessChat(AspNetWebSocketContext context)
, U# K8 D' D" g - {
5 s% A8 ]# X" W7 B" [6 E$ u - WebSocket socket = context.WebSocket;
" G @: }. m9 ?4 T4 Q - string user = context.QueryString["user"].ToString();5 K0 m& C" }$ a- J) E; `
, i+ f9 f. w/ T+ |% l, j- try; i$ d$ m2 q/ l! @7 |. X- t; M* @! c' s
- {
9 F. j6 s! @; z/ }' l - #region 用户添加连接池
3 H" y# I5 C' [; } - //第一次open时,添加到连接池中
7 ]/ V3 b& p/ ] - if (!CONNECT_POOL.ContainsKey(user))
6 K9 T: ~. b; @% V, _, z l' { - CONNECT_POOL.Add(user, socket);//不存在,添加
+ B+ B. ~' F6 s0 W, P - else. F0 U9 B2 z/ o: I8 z+ F
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新2 ]. r4 _8 X. x! Z* E7 }, L, q
- CONNECT_POOL[user] = socket;
6 q, ^- N. b8 S2 G7 I) r - #endregion, M; T: E, u/ z& M! [
9 [1 v; {5 f+ N: l% a- #region 离线消息处理! R, U1 o( O, \+ ~9 v
- if (MESSAGE_POOL.ContainsKey(user))
* r9 a8 k# f* H! x% Z& G# x* b - {
& ?$ `+ x. H | z4 U+ c! X9 A - List<MessageInfo> msgs = MESSAGE_POOL[user];
* h8 C; @- o& S6 u- X+ t - foreach (MessageInfo item in msgs)$ L) d9 g& E8 _5 x9 v
- {: Q6 R6 i# a# b# v, s1 H/ R* r* A
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
+ A# M0 |# a* a. v6 d0 b - }
8 \- Z2 }: W9 \$ K$ o - MESSAGE_POOL.Remove(user);//移除离线消息
5 {4 N7 [; h0 c3 f5 Q; }, v - }- I5 s- @5 b. v
- #endregion8 o7 D1 A" Q2 t) c9 \
- / @: V9 g- |1 k, m+ V& j7 t
- string descUser = string.Empty;//目的用户
4 E8 f) P- @: I3 U - while (true), [9 ^7 G2 `3 K c9 X( i
- {
5 u1 H$ C7 u. {& [# j - if (socket.State == WebSocketState.Open)! a" e# w- V# k- K n
- {6 B: k- N# P; }- Z' L
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
& v0 p6 L) F) ?+ }; Q% u$ o9 m- { - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
7 t" k, [7 O% f& _: }
) Q9 C! d3 V6 {7 ^+ s- #region 消息处理(字符截取、消息转发)
+ }: P2 U/ r) P& F" `0 v+ a7 t- s% c - try; d; z; P% A: N7 q& W: J. k' X
- {* X5 b# }" j O5 z) v# P
- #region 关闭Socket处理,删除连接池3 y8 g, j4 Y% h; E+ L" x
- if (socket.State != WebSocketState.Open)//连接关闭
1 R* r# e6 a8 q/ i" n1 H" u* E - {! G8 L }( I; D# S2 H
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
, S7 {9 S* z/ u: D3 F - break;; ^- [# `& o- I$ O
- } {& R: ]( C6 C# x: a8 C9 }
- #endregion; L$ n; g5 ~1 ?7 O9 J
- ( s [& E0 q' g
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
, w, D+ u5 j$ x3 c4 k+ _' ^ - string[] msgList = userMsg.Split('|');
! K1 `* d+ o) |/ l" G& q$ f) Q - if (msgList.Length == 2)
) v/ k" I+ s' L' B5 Z - {; H( ~ h) V i1 T2 U5 x3 l
- if (msgList[0].Trim().Length > 0) [. b1 H$ I9 E$ q# K
- descUser = msgList[0].Trim();//记录消息目的用户, q9 P0 g' B! o4 U2 u- s
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
2 t- o% ?& W F# Z' N3 A6 L4 T9 p+ V - }
$ {7 t3 a6 Y9 u - else
, ^& o4 ]4 J& Q5 J: c - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));0 K+ c) r* ~3 G4 h, W; I3 v
- ( J% R5 n3 a7 R1 j; V
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
+ \& M. J {0 d# F - {1 C& v: w3 B) ~* R
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端' M4 e5 \2 I+ b m# O
- if (destSocket != null && destSocket.State == WebSocketState.Open)
@0 H* u; C: v* P3 _ - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);+ U. l/ L4 F8 q( E
- }
" D5 P* G/ x$ I, v - else1 H* v( W' @ Z: U# } g$ Z
- {
. o& B% _+ J3 k# i% Y3 @ - Task.Run(() =>
: ^! U6 G) W; c: N. y5 X4 j - {( |! H' J9 i) }/ ^% K# R; B
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
1 l! ~: q# Z8 @+ }7 j - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());8 g8 n$ [) n9 n( u# N6 K9 ]8 u
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
5 I! f- m, k' i8 h Q7 l1 i3 F - });6 m/ M% ~0 D9 ]$ U) R2 V
- }
0 ~( r' h9 ]$ P" S( q) W - }) ]; \- Y E! u; V+ a. P' x
- catch (Exception exs)
/ x5 C6 _! |: ]( P - {
1 _- g: f$ o8 B: L - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
0 E& f: l9 O& {! B0 { - }; N ]6 d% d* k8 h+ J( O
- #endregion: j! N1 E- z, R: ]
- }
+ r( ^. q- s9 P @: s- ^7 A w - else# P, r2 \2 i1 o6 \/ q& I5 y
- {
7 ^" r4 a+ _# B I* D! [+ | - break;
! `2 b& {2 U9 g7 i" `- H - }
5 a8 ^ u, t5 P# r* x; L3 q - }//while end7 M8 c3 ]; _* }7 u4 ^: c" r4 R
- }6 o) _ O8 u, f' Q
- catch (Exception ex)
$ d' N; S) o- X! T4 ? - {. N( \* ~. G( a$ b5 w/ c* r* ]
- //整体异常处理+ |& k) ?6 k9 [3 P( N. W3 {6 Q, l8 I: E
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);" ]8 }7 T. [& J8 [
- }
1 A& X; L9 S* C( T2 ? - }1 ]- D2 V: M7 a. P$ U P# ^/ g4 E
$ O: V$ K1 Y% E9 U2 Y6 D- 1 U* F# C, c2 k& }
- public bool IsReusable
. d; }& U; e5 V4 H. P - {6 {+ E2 ]( J- r) Y; g3 \/ n
- get
& _$ r( ~) |, B8 z - {- | H/ D, L+ L L
- return false;
! z y6 i4 m; w. U% l4 w1 j - }
# ^% d: f' }. K& N" E$ h c& ~ - }" o2 Z: ?. j8 s8 ^8 O. o) Q% _
- }, N7 {9 M- X/ z' @; a- d4 G
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 7 u. v9 s- O2 i f5 b
|