|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 9 \5 E; g' @6 [$ b% x& s* v; ?% b
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;# y+ B! \& \7 C" @
- using System.Collections.Generic;
m! R8 ~* c& E! l. [& ]$ u/ d; O - using System.Linq;9 Z0 P2 l6 @! U1 j/ D/ M( v/ n7 D
- using System.Net.WebSockets; ^; y: a% C: V u/ z" `6 O
- using System.Text;
& R2 K( K/ i6 }* e/ @ - using System.Threading;, E2 a+ Y2 ~ P
- using System.Threading.Tasks;/ Z/ s5 [' D' _( \
- using System.Web;
' L3 a" S$ z/ D$ b6 ~ - using System.Web.WebSockets;5 F& Z0 P( x- P1 x* f5 f+ m! }
- & N# [/ D" |* z: l( M) W! D
) Z; z) U9 W3 B- @3 M7 V- namespace WebApplicationWebsocketHandler
: ]: h5 ]6 k6 [: Z! A' Q5 S2 E - {
, h2 Y$ s' y/ D3 v - /// <summary>
. w/ e( Z, ?7 m+ d: [0 {; O( A+ K4 N - /// 离线消息$ I- Z/ u6 f2 @" n( m0 A6 i, l
- /// </summary>
4 c8 A, V2 w7 ~: ?$ I& d. y - public class MessageInfo G: | U# ^3 u \1 L" ~
- {
9 Q5 I, q, B4 R R% I$ i/ y: m - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
1 p! y: F' B$ a0 x9 I; S - {! w% N' p S* H# x& L
- MsgTime = _MsgTime;7 L. f1 f# ^. B8 u( t# S7 F# A1 u
- MsgContent = _MsgContent;; `8 Z2 P _3 G `! r$ i0 s
- }
, g1 x. `: c# o2 H - public DateTime MsgTime { get; set; }& Q+ E4 Y4 Y) o; y( ]
- public ArraySegment<byte> MsgContent { get; set; }3 U3 t0 O: [1 F- q' K+ v, s
- }- z* b* D* p6 @* o/ [
- ( o* A g0 `+ t! r% J! W2 ~
- / e) M9 w3 M+ L
7 X8 W4 |5 J. }2 t- L$ H- S
$ {; @* I+ e* D9 M! M/ @! b; {' x- /// <summary>
% Q1 f, |! Y; G( Q' Z M1 C6 y - /// Handler1 的摘要说明
. ], a! W, l! p8 p" s - /// </summary>
2 m" h" q6 G ~0 e$ W6 a' U - public class Handler1 : IHttpHandler4 }! E$ f! @. [
- {
) i3 Q# b4 E8 ^# j, ?6 ^, Q - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
1 _ g5 O! U& `$ ? - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池( Y5 N3 N# L- A5 O, z
- public void ProcessRequest(HttpContext context)
. Y) x5 Y* V+ p T2 Y - {* F0 c+ Z6 H+ f% Z
- //context.Response.ContentType = "text/plain";0 p/ O6 C! z: e$ D& z* `
- //context.Response.Write("Hello World");- ?! p, I: P. `0 D; _6 g7 {
- if (context.IsWebSocketRequest). n3 f' [0 N6 X# X2 T1 f2 D
- {4 Y* m' y0 Z" g6 k: [' g
- context.AcceptWebSocketRequest(ProcessChat);# D. C' c0 p; L5 x$ L; y# N
- } : X8 \: n$ |4 |5 x2 o5 e8 W r
- }7 I% M: @; P T# L5 P6 _4 g
( M& \, q( v5 ]0 D- private async Task ProcessChat(AspNetWebSocketContext context)
+ n" O* I% ]( Z; `: v* \$ c: d% S - {) M, {( ]8 k- C( c9 b
- WebSocket socket = context.WebSocket;0 h1 d9 C w" |& P4 A; E& }
- string user = context.QueryString["user"].ToString();
; t) f, w, c3 i8 m) s% F2 i - " N- q a9 d$ N d& i6 o' u% Q
- try
8 i/ v8 D; [, Q$ J; | - {& I- ^* T" V) L. z0 H6 J
- #region 用户添加连接池
7 K1 ~! n Y! Y3 |* j- @/ | - //第一次open时,添加到连接池中
$ u* @) ?% o; e2 Z) ? - if (!CONNECT_POOL.ContainsKey(user))
0 b. l+ E$ d( _ - CONNECT_POOL.Add(user, socket);//不存在,添加- ]- N6 f" O+ \/ J! n
- else
4 h: c' H: |1 d$ B - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
4 p: }% R$ j4 u - CONNECT_POOL[user] = socket;
0 W' v) L& `* ~# b; |- V# i - #endregion
( z6 s2 l. L( L S9 z - . W" P* P, y( Y0 Q2 q
- #region 离线消息处理
+ I/ Z: U! Z* Q, b7 ~1 r - if (MESSAGE_POOL.ContainsKey(user))
0 ~2 s- L5 C l1 P/ h - {
* Y% {" H/ K! M0 ]& j5 {6 Z- b - List<MessageInfo> msgs = MESSAGE_POOL[user];
?$ B! T; [7 X$ t - foreach (MessageInfo item in msgs)
" R: g0 A7 ]1 Y5 X5 Q' Q - {
' d! U. F1 r0 F8 g - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);! c9 P0 }# {9 X. c' a# i& `, C
- }
9 ^0 X* s$ B" Z) ^. s - MESSAGE_POOL.Remove(user);//移除离线消息) O5 R: {0 v ^- |( ^, y7 J
- }7 m5 {* c% B0 v7 m
- #endregion
2 O* V9 E, r/ Q0 z& R7 J
% } c3 U, A* `& I- string descUser = string.Empty;//目的用户; f. D/ y$ j+ s0 m3 p6 a
- while (true)
' D3 s/ r1 |, y v2 J - {7 N) x2 |" d2 G
- if (socket.State == WebSocketState.Open)
1 Q! V( s$ ?5 {: a* H" a0 h - {
8 c: x) b" R$ Q) k, d! `. i8 S: e - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
; z9 w- u* @8 s0 D - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
" z, I1 y8 t6 C3 @ - " _& ^% n- o! M
- #region 消息处理(字符截取、消息转发)) l# V8 r# S- K( C1 c! [
- try
; G8 |0 B, L. C# k) o' { - {+ g0 l. m- J9 ]; P
- #region 关闭Socket处理,删除连接池
4 ?; n f h# j" q9 U* t7 ^ Z - if (socket.State != WebSocketState.Open)//连接关闭; F$ a, v2 s e$ y) w1 s0 m
- {" [6 g: A, M4 E- y a
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池6 ~( j) F6 c! ]2 G4 U) E0 F
- break;
' V9 T; _3 C) E9 K' P - }
' V" t4 a# P7 c2 ~+ ] Q - #endregion1 ]3 B7 q G, z( r; @0 E
" e. D, H7 G& ~- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息: U$ K. V2 Z2 E( m4 j
- string[] msgList = userMsg.Split('|');- _% k& C( H: b
- if (msgList.Length == 2)4 h2 S3 F% [+ |) J
- {+ Z: u+ v' o+ N2 f
- if (msgList[0].Trim().Length > 0)5 z% L+ r; h5 M o! E! A
- descUser = msgList[0].Trim();//记录消息目的用户3 g* o+ [- x# T4 x
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));+ U* A+ D. D2 \" b0 W
- }* ]1 j8 W/ N% y2 m
- else% T, _) A6 F) k8 G" N s9 C+ n
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
3 `9 n# u" I" X% _) ^
! C/ v$ `7 H" D- v9 n- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
$ w r2 A$ p; D9 _ - {! h1 p! W: ~- g5 m: t
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端: y2 Y' K4 D8 t, I
- if (destSocket != null && destSocket.State == WebSocketState.Open)
' f, p, Y) |+ h - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
. Y8 B* ]1 Y# F/ _& e. `+ h& k- T( W2 g - }
9 N+ s& @. d" ?; V/ |2 { - else9 }6 w, H' C, y6 H ?
- { S: _4 D. S3 z& X7 i8 D( S
- Task.Run(() =>; O/ R, ~+ ~* s) q& Z
- {
7 [$ \* ^& R: y: u - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
2 U1 l2 g5 y7 {# |1 m, k/ Q* X - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());5 n1 P# p }+ \8 U1 }
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
! H& ~4 U n. d4 d: D* X - });0 Y) N" r0 |8 ]# A! A% e
- }# `0 Y! G; l( t+ j$ { `
- }8 W( H* K- T/ q8 c/ u0 T( c# r% K
- catch (Exception exs)
' s) e7 P# u& ]5 n. Y& R, I - {( J) i q# m2 p5 C2 Z. t% s8 C. q
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
* Y- h+ |5 |. T3 Y: z0 ~- ^1 R- O - }! ~# v; @4 F; k6 X9 r4 u& J
- #endregion
! r" E4 r& k& `9 R- @; k( v$ D9 \ - }
1 a, l1 N# f0 U M" C% m+ u, G/ p/ e* l - else6 b% ^5 M0 q# U/ w
- {% \# c% x# W2 u1 m: n7 u9 j
- break;( ^- M" X h* a8 v( i
- }
% K b% b( x& x4 S - }//while end
) D; b' J7 \7 m - }
- y0 u! E( z7 Q) p, W& e - catch (Exception ex)$ a! M$ H/ ?: ~6 v& A6 p, ]
- {) v. @; _% H2 e7 B: l: ^( N$ x6 ~- Y
- //整体异常处理 \: M" J6 L0 Y1 s) Y
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);' a6 l) ~3 [, q7 q
- }
% E% U) }) T- h8 X8 v - }
. X4 Y+ c8 ^- |* [" _, ` }
o9 E/ N2 S+ h+ p" `- % }7 i( `9 h7 z% w
- public bool IsReusable
. z8 f1 Z3 H# \ - {9 |# N( L- H! a. c* F( \
- get1 m+ y9 r( r/ B! d! d# m
- {- c; J: {7 `& o! W8 O
- return false;
- g3 ? a: H/ n5 v - }4 G% ~4 u! {2 L& I' l/ n0 B2 a: `
- }
! f4 A; u& `6 X: Q# G. Y' N - }' N* P8 ?" I, H o
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
. Z4 n- _. \, T# A |