|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
! S6 l9 q3 z% n2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;; `4 F3 E$ B# e* p$ ^$ F. k- `/ B
- using System.Collections.Generic;7 g! F F: ^$ ^ ?# R. `
- using System.Linq;2 M( k) w7 P3 L0 u1 Y( d% x2 r* I- d
- using System.Net.WebSockets;( l$ a V; w" X( e$ z$ W/ x& x' l6 Z
- using System.Text;/ C% x# l( u4 C# [
- using System.Threading;) |% |& F! U8 C
- using System.Threading.Tasks;' j0 K/ Y) d6 o6 E: O
- using System.Web;
2 F0 o2 n2 F" q6 ` - using System.Web.WebSockets;
# {1 ]8 g- W* B: q) v! W8 t, N2 f7 | - 8 Y7 q1 h! q f
- 5 p% u0 q1 c5 b4 u
- namespace WebApplicationWebsocketHandler1 K- \# ]! }% b
- {& B3 n% q7 q* U
- /// <summary> W K; _9 _2 p; ?9 T9 ?
- /// 离线消息
9 I! j+ R. p9 O+ ^$ ~& n. v! q - /// </summary> D6 y* D. B. y% Y5 g5 [! X
- public class MessageInfo' R9 I' {: Q4 w- i" c2 ^
- {
3 C" C$ y5 l- ^: Y - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)1 X, M$ H7 O3 v0 P# ]
- {
: l2 x* O" n6 G& Q* N - MsgTime = _MsgTime;; [7 ]1 q) e1 b
- MsgContent = _MsgContent;
5 @3 _+ T! k7 i9 l) K# j - }0 A. o ?. q% ?8 s1 ?2 r! w: j
- public DateTime MsgTime { get; set; }
; {4 Q1 `+ e) t& D N - public ArraySegment<byte> MsgContent { get; set; }
/ b# x7 R% B0 z! l: h; ]3 R - }
! U* w& a5 A8 `. t - X6 I x3 r) ^% s3 J
8 r- C9 Z' O; E- t% W2 l- " m2 `3 E/ z! \4 m% N6 P
- 9 P T9 \+ z, u _- m
- /// <summary>
& T: t. F* B9 j - /// Handler1 的摘要说明
7 D7 z% m: q5 ^) X( t - /// </summary>" G& P/ I2 p8 G
- public class Handler1 : IHttpHandler( ?% h. A% u- Z" }3 C, r
- {/ B' c. {' ^( p! k4 I0 ~
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池! A; ^, }6 p$ V8 q
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池' d4 H9 \0 B9 e' ^# i
- public void ProcessRequest(HttpContext context)
5 p% M9 t/ q: y1 E - {3 W# H! K, \, ^# ^/ y
- //context.Response.ContentType = "text/plain";
- J6 h; E$ @6 h& T' y, V - //context.Response.Write("Hello World");
/ p$ g1 ~7 F! A - if (context.IsWebSocketRequest)' ?0 w* j" o2 m3 ^
- {
! {: |! A6 M5 w1 J/ H" X - context.AcceptWebSocketRequest(ProcessChat);& P: a$ I' ]* i( g6 a& x$ Z! W
- }
5 A, D5 c5 Y) N! H+ M( l! C! M% \ - } H& G8 K3 K2 J2 ^1 V3 n) h- p. y
- 3 E0 m; `8 S8 k* A2 c4 C, x
- private async Task ProcessChat(AspNetWebSocketContext context)9 x+ \' ? s W
- {
8 T* Y& V4 V/ B3 Z7 W. I) s. Y1 C( V - WebSocket socket = context.WebSocket;
, |- D! { k2 k9 b9 j5 m$ z5 j9 Q - string user = context.QueryString["user"].ToString();
t4 ~/ D/ q( J6 g9 ?5 ?' n - * e+ y1 m" A* r6 N: f+ o8 o
- try
) A1 J8 W0 [2 A; q# x1 K% R - {
4 k1 W1 m: U" G9 e - #region 用户添加连接池. ~+ B2 w5 C: k9 k* p
- //第一次open时,添加到连接池中' a! l' D+ b2 \: i$ t" e
- if (!CONNECT_POOL.ContainsKey(user))
- Y9 c. q( x+ U3 v' W( v, g - CONNECT_POOL.Add(user, socket);//不存在,添加
( Y$ z0 C- J$ {: s4 T5 z& @ - else
7 L8 w5 t' w3 c0 [ - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
' n" E q% Q3 D8 B1 X0 P - CONNECT_POOL[user] = socket; P5 T7 ~" o+ a4 e
- #endregion7 b! N3 a; }( a3 e4 j
; N$ i5 o0 D5 ?% C6 l4 E7 g, |- #region 离线消息处理0 }$ F8 `' M2 k, q: Q0 o( Y
- if (MESSAGE_POOL.ContainsKey(user))# e" Y! M1 `/ K5 S6 }5 {' M
- {" g% R9 r# F8 c* F+ |) ]
- List<MessageInfo> msgs = MESSAGE_POOL[user];+ d7 n& J, z W( D' q' I
- foreach (MessageInfo item in msgs)
9 t" U8 v5 g; P0 g) e% Q - {
; H) v& m' b/ C$ R$ v( Z - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
; I L7 l. L9 X( W4 t2 O - }$ }( t9 H8 d2 K! I4 B: d
- MESSAGE_POOL.Remove(user);//移除离线消息: ?7 G+ G( Z: _- V; d. U9 u
- }
% i- a8 t8 z9 p7 c9 h - #endregion; g. p6 l$ X" |; M. R
9 ?/ F% ^6 o5 w# ^9 E# f- string descUser = string.Empty;//目的用户1 C. B4 X7 V5 w" r
- while (true)
) ^* [, N! ?9 o1 g Z8 C3 J' @ - {. K# R: L6 _) R# V- H' q
- if (socket.State == WebSocketState.Open): u1 T P4 P2 H
- {
: C0 T" S* S0 d$ t/ N" \- s - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
5 ^# X8 {6 `3 E1 x1 j! i - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);2 V/ D8 V [8 R) H, N% h2 z' s3 W
/ m" e8 _# _5 q- #region 消息处理(字符截取、消息转发)
$ h& E6 p! H: v: g4 Z" A7 f - try
& l6 T7 u* X6 n4 z/ y5 Q, Y0 h. C - {- y; w; [- p6 s* F+ Z' e% `) ^. e
- #region 关闭Socket处理,删除连接池
: K8 D8 x! h% A) V6 P6 T - if (socket.State != WebSocketState.Open)//连接关闭* R8 ^ a2 Z8 @" E0 l
- {
! f/ K M0 q0 C. ?' r" | - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
: }3 {! {0 `. X1 u3 c! V - break;
I! k" ~' f4 ~3 b# X - }# F, Q5 u2 Z$ W5 | ~/ l1 H
- #endregion
: p) Z% i; L5 |* ~: x - * H o. c6 U) j
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
5 W) ]6 C2 ^; L# o - string[] msgList = userMsg.Split('|');
' W p. T. N2 S5 t& ^/ a, K/ P9 E - if (msgList.Length == 2)$ p6 z1 y8 s, z7 r4 r6 t
- {
% @5 L3 N, e2 ^) @; H9 K - if (msgList[0].Trim().Length > 0)
, q4 S) w! m3 _0 [. q" D - descUser = msgList[0].Trim();//记录消息目的用户3 N$ t; S2 y( s, z
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
. G; v n: g% k; Q - }9 T7 [6 d+ _, t& r
- else
+ X: c# X. s* @ y0 a7 [& ]/ E - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));; `. F" ]" E- s2 D& d0 K' S: U
: i7 G) p3 j3 W. q5 O1 l- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线9 ~+ O. ?# Z$ X) \, P
- {6 h; h+ f d$ o
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
/ n2 u1 K5 z4 _5 k, t - if (destSocket != null && destSocket.State == WebSocketState.Open)
, H0 W8 L7 M7 z5 h7 q" t/ C - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
- p( K* _* Q$ W) Z# a7 T3 ]+ K - }- c, P5 @; c; W+ ]
- else
$ y/ A# V' U$ u' p - {9 Y% `; a N3 B' G, k H: {
- Task.Run(() =># s9 ~: w& B, r6 b! K; d% O" B
- {
0 k3 U! c/ b O7 _+ a- ~ - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中/ y) w+ E* e4 E% N+ {; [8 H5 m1 p
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());' L1 W% N; }: O" ]3 S, P0 P' c. Y
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
+ ~: I; x' r- `4 ~5 ] - });+ f. L. [" f% V/ f9 T* B
- }
# j: X- J2 m5 t - }2 }; q! _( l6 z* b5 B `! a
- catch (Exception exs)3 _! Y) N l- s r# B9 ^
- {
) v+ _! S5 |% S; H/ h" G% X# \ - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
^8 G' a4 J( t* M3 q - }
! u8 Q' L+ q; E8 p2 O& v - #endregion
0 x+ c* _2 {/ w4 X$ G' |, C8 q! S1 [ - }8 W% x/ Y. G( W. K- X! _ K( l
- else
8 V) J7 z2 {# u: i1 A - {. S+ Z; G8 B/ G& R# ~7 j; a6 T
- break;4 `* ]/ q) J m/ \7 e" _+ [4 [. h
- }4 f- E8 f4 g3 B4 w0 D" k* n( q, ?
- }//while end
( _* p0 E3 |/ G. }1 H - }
7 R: \* x# p0 z( D - catch (Exception ex)/ ]& W y0 J* m! m
- {, w1 l2 j# M- ^. Q1 a
- //整体异常处理3 K" m8 y# N; Q
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);3 i! X- D( M* a% O8 Q: _2 [
- }
8 e: I% O; s7 B! k& W) X' R - }
) W6 {+ Y" O( Z! g; |3 V; p - 4 o: U: ^* _- Z: R/ o
- 7 `3 g% j' [- ~+ s
- public bool IsReusable
4 t0 ]( ^0 g( d" ?9 U/ o - {, `6 T1 W. Y( e) Y) x- G8 M
- get
( ]) @0 p. A4 c( H4 }- Z - {
& ?1 V# b* w- O4 [5 A7 J6 F: h - return false;
0 _; A) k2 N3 n7 k9 o - }
# ?! |4 I4 { U/ K( h& L - }
2 | O1 b$ D/ L2 m- Q - }0 F" y+ J( [2 P: n7 W( R# ]
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 : P) L+ \( J2 H- r4 O( m# {
|