|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 / V9 ?9 i! d( t; b& f
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
3 @5 v' J7 y' @, u3 I; z - using System.Collections.Generic;* S7 m+ o: x: |& @
- using System.Linq;, z" z: |4 q' C
- using System.Net.WebSockets;4 I# {# N9 H$ ^3 i
- using System.Text;
, T& k6 L6 T g+ z) X W9 @0 M - using System.Threading;- D! a3 U) X8 \: o2 q6 R
- using System.Threading.Tasks;2 y8 i9 n$ @+ J, U% ^
- using System.Web;
4 ]+ s; }' k! D& d+ N0 R - using System.Web.WebSockets;
& K ?' X) y0 N2 v B, Z7 X& {
~# r( E7 V1 y4 p9 a+ }- 6 _$ Z5 u _) W6 j( ]2 k
- namespace WebApplicationWebsocketHandler4 m$ l1 G: O# {% T
- {2 B" C% R5 f1 Y4 j( l E, _: p
- /// <summary>) X1 s5 S4 Z# t. m7 ^
- /// 离线消息+ @* S7 _7 H! o
- /// </summary>) d6 K" H, j* t) \2 Y: r( I
- public class MessageInfo% v [% C# u, Z
- {
7 u: {6 c) e1 m' D+ Z' x( q - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
. t( u% ^# k3 E% d9 q8 ]$ K - {5 p! @% P% E, t s
- MsgTime = _MsgTime; X& @8 s1 P: _: ^, V
- MsgContent = _MsgContent;) h5 f; }1 k, ?4 A3 k* M' v
- }
1 w5 y$ n$ t0 i2 K/ u8 Z! u - public DateTime MsgTime { get; set; }
. Z5 c g, R- l6 K" u. Z( Y - public ArraySegment<byte> MsgContent { get; set; }1 B4 r" e7 T' G+ `4 J
- }" r4 {8 X0 A! C- l( O. J
* ^0 ~2 y+ Q B, ]5 ^
+ [0 j1 N2 g, w; s! x- $ l5 O% d k% {" l6 O. b
- j) u5 d) \4 g- /// <summary>2 p5 v& G) N& t2 x
- /// Handler1 的摘要说明. V8 B/ C! p& f U2 T
- /// </summary>
' N/ \) V5 m" }$ o1 v$ j$ T' {5 h - public class Handler1 : IHttpHandler
% D9 j% P$ f4 @9 E. C; ` - {# S: S9 ^) Q! m. l
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池1 B+ j0 U% d! g8 m/ d x Y
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池: u' f+ l1 F1 e$ k
- public void ProcessRequest(HttpContext context); G8 N1 U+ y% `3 ^: v; p" ?
- {
* a, g! o7 l2 F2 o7 H( W( ? - //context.Response.ContentType = "text/plain";6 W0 y8 V; b7 V2 g' |6 z& V7 J' m
- //context.Response.Write("Hello World");
2 l1 U( {6 \0 N, ~* e - if (context.IsWebSocketRequest)! n4 ^. h' h) [9 {
- {0 _: k3 v$ d3 l- t1 r$ }
- context.AcceptWebSocketRequest(ProcessChat);
$ n+ i4 a' l. F# p, I2 o( Q6 ]. ~ - }
& H+ n1 a8 P3 ^: i3 _+ g6 ~ - }: w; w# U, t9 A5 x
) b6 @/ x5 Z2 g6 n; ]- private async Task ProcessChat(AspNetWebSocketContext context)) [ B% m6 {9 i. T4 L: h
- {
' p, s( l2 d$ k - WebSocket socket = context.WebSocket;: k1 o& F" a( w; X, L: y N# f
- string user = context.QueryString["user"].ToString();
7 i* ]4 y- d' d
4 Y8 j/ j7 X q# @* m0 t; X- try
0 Z4 J0 a' H5 a z - {. [! U( V x' W0 S# p& c' R
- #region 用户添加连接池1 E5 ]6 D+ h! \8 ?" B# F
- //第一次open时,添加到连接池中
2 ?1 l" E1 B: @) c( Z - if (!CONNECT_POOL.ContainsKey(user)): G+ w- L4 Q! [
- CONNECT_POOL.Add(user, socket);//不存在,添加% K6 ~: e) u5 x) j
- else: g+ h) d* c. ~# F l5 U
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新8 _$ L4 {$ I/ i9 Y5 h+ i; ~
- CONNECT_POOL[user] = socket;
( `) {/ F: `9 N$ \+ h5 J - #endregion' e" I7 C% X7 O+ @+ V" q
- 5 G! `* W6 U! E. R$ I/ _0 A0 u
- #region 离线消息处理
! D8 |8 @, t' \0 C: x' Q7 O - if (MESSAGE_POOL.ContainsKey(user))
; V2 K8 b1 X/ q* Q/ L - {
0 G, G' U; e: }9 I - List<MessageInfo> msgs = MESSAGE_POOL[user];
# ~- q4 G7 _2 R) @/ F - foreach (MessageInfo item in msgs)$ _" [% c0 x6 C! v" X% y n# T
- {- ]9 t! W1 z0 `: R+ a8 e
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);$ {# h% E+ S" x7 q' _$ q; Y
- }* V3 g$ I" V# J1 f6 r
- MESSAGE_POOL.Remove(user);//移除离线消息
) r6 w3 Q4 t! t$ i. N - }6 ^1 ^9 `+ E8 w& G1 h) D5 S
- #endregion
\% ^4 f8 O* f! Y( J+ [ - / M, b: O2 y$ n
- string descUser = string.Empty;//目的用户 C& E) T( i. k$ Z! K# z. C- e
- while (true)
# j% j4 R+ n' v+ A2 ]6 h1 J - {
$ ]# e9 c' S% n L; j - if (socket.State == WebSocketState.Open)' L" ?/ P/ B: w9 `
- {4 z% D7 }( N5 w" s
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
$ P% S* I* Q5 ?9 D$ I - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
+ X" @0 Z+ l9 t; f: u - r8 ~( J: L" X, E% s
- #region 消息处理(字符截取、消息转发)
" m6 i6 N" {. k: A8 ~) G4 g - try2 o! ~& a2 c0 t% ?4 n9 |
- {" D. A/ V! j' F! G7 Y
- #region 关闭Socket处理,删除连接池% Y, g9 w/ M/ `/ @
- if (socket.State != WebSocketState.Open)//连接关闭
2 f3 g2 f9 W+ X O# u1 H - {: N$ t/ d7 {% [0 A5 z- |* ?. R
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池2 _# t* V0 d4 x" {$ f3 O1 J! a7 {0 w
- break;
8 g9 S: ~- n0 F) k1 S - }
, B, M. @% D9 y4 i# A2 F( E, ^! h - #endregion4 L4 n! M. }' S+ u
- 2 u2 X* {8 T2 e. u' I
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
& ]) o! T6 A9 w( ~3 ` - string[] msgList = userMsg.Split('|');
- P- ~' G% T' z% J5 d - if (msgList.Length == 2)
& i; L' Y* v. f" ~ u# g. v/ z - {4 D6 h' T$ x/ s4 J/ ?/ J
- if (msgList[0].Trim().Length > 0)& {6 I' x: g/ o4 L( ~
- descUser = msgList[0].Trim();//记录消息目的用户, `* n7 M" e# Y
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));; x" T$ m' a3 M; N7 d( e. U3 F4 l
- }
) O3 M! \9 A) F! o5 g% H - else: T; X4 e3 F; v5 g
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
! Q+ u7 m' K9 y! B' r
# p* }8 O3 r3 _* G- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线1 n, d' W M" m* B
- {
3 k) u* c% O/ {' o: \# k - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端8 a5 \2 Q5 h8 V7 x9 y) P
- if (destSocket != null && destSocket.State == WebSocketState.Open)
- w5 [" b4 V6 ? - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
9 u* [% _, X; T' S# g5 z3 f7 K; E - }- v' g/ B9 g6 j1 C- L- d! w
- else
8 ~! R1 m) _) @8 h2 x - {
q; W' T, J- R4 ]4 u4 t+ a - Task.Run(() =>0 e" d0 ~8 ~5 [' u( o' d
- {
+ @9 F$ z3 e- L8 h8 ^4 d( m - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中; q/ o+ r3 p& g8 i% X& A, e8 N
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());( z+ F: k6 K9 |
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息; V) H: `% }' q6 g% A5 d* p& l
- });
7 M l' \, j/ c0 Y- _' w: {# ` - }2 z* |- _/ Q& C# B Q9 [# G& N5 @
- }
: B i$ i* I/ `* B0 h/ T - catch (Exception exs)
v# r$ d% F; ]* t+ m& P4 z, P - {
; T2 R( _' s( B6 S9 A3 C - //消息转发异常处理,本次消息忽略 继续监听接下来的消息$ p7 k6 ?) S3 d6 I+ d2 q" M" w
- }; P! E0 }( h( O, B, o1 G
- #endregion- K, g1 D% \0 W' G# O: `. V$ S6 t
- } _ G! e" S8 v) M, R9 f+ Q4 u
- else
% {8 S: _4 k1 n9 y' Y$ W- W - {
) ]$ k% H6 m0 [7 m' p - break;
8 S+ g7 w1 H' }) E - }- x: }4 t7 W0 J$ V- ^- F
- }//while end
! J5 t" S& ~. v+ b6 L8 [ - }0 U5 ?4 S" {1 x, q( }& w5 `
- catch (Exception ex)
9 o7 ?; d: ]6 r# m( K+ d7 J- | E - {
( x5 ~ V8 ~$ X: l - //整体异常处理
4 t% _. d' D/ T& C: w - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
b/ Z0 Y' @+ P: y - }
4 E; P' ^% F' G# C9 e: H - }
2 @0 z' D% \3 H/ j - 7 D: N9 D7 r% \" f8 E4 A( c8 Q- h3 m
- - n4 Z7 N2 ?' O9 S3 ~/ O3 v
- public bool IsReusable0 w2 X! q: i0 h2 Z
- {
; R( o5 x2 s0 d- B9 n% \& [ - get
1 j, ?" F. R3 u1 W9 h - {* W0 {6 {, ^ ? a. k
- return false;
3 D8 E, m- M* ~0 s( e6 d+ {, l$ z" t - }1 {4 i5 m& l1 p: q: S1 I
- }
( F0 p# o8 [0 g1 s: j - }6 I% `! X, S! \. C( o/ H; H7 h+ c
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
2 S( b9 d5 [4 ?* V |