|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
. C* ?7 F- _" k7 L* u" ^2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;/ s* S; r* u" G5 W2 E
- using System.Collections.Generic;
N0 }/ A" ~: N8 n+ N - using System.Linq;
8 |7 j- [$ k2 @$ K4 T - using System.Net.WebSockets;
0 S& `5 z4 t$ x/ `1 e& x - using System.Text;% [2 f& L: K8 V7 |
- using System.Threading;
( J6 f: i3 h. T8 I, ^ - using System.Threading.Tasks;. [. g9 d" N$ @# X/ \ o% {
- using System.Web;
; b% l2 g9 [* u" v% h" U - using System.Web.WebSockets;. Z( A6 W6 H9 h1 `$ }0 {
6 E/ ?4 i/ V' q# M F# z# q: A0 @9 D- 4 s' R0 |) Z3 ~& d: B
- namespace WebApplicationWebsocketHandler
o. m0 T4 p/ Q7 Z8 F _1 L3 t0 O2 t - {
; C6 o! [3 _( ~5 }. h" G - /// <summary>
+ k0 _1 u- K* b2 @" Z0 m - /// 离线消息1 O9 \; e% ]* l1 _( n+ b
- /// </summary>
( Y: x. ]+ G- h5 N - public class MessageInfo
- y& y4 M% \! V% F7 l* x9 U2 Z - {
" D3 k2 R+ u# q6 } - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
) n5 Z& ^0 {0 ?- T _& s( f F7 L - {+ r2 d$ d* D# ]
- MsgTime = _MsgTime;; x8 l" j7 x( { S
- MsgContent = _MsgContent;9 g, f4 S! a6 p# x& E1 l
- }
$ w2 ~' g: k& l8 v5 ? - public DateTime MsgTime { get; set; }* D; R! e* z- ~' o
- public ArraySegment<byte> MsgContent { get; set; }& ]: [6 E# K! L3 ~
- }
$ K0 ^" x1 Z1 I5 u5 U! b" W7 ] - 8 r1 Q* w2 B" W* I" x
- / ]) y! q/ K( _* u4 N! ]" a
% ~# R- y5 H+ ?; p3 f- ' ~2 t3 }5 E0 W4 C$ ~ @/ r
- /// <summary>% Y( @ v) ?4 ?% U( k
- /// Handler1 的摘要说明( J. x/ j* d( G+ ~. F- l1 ~- w: G1 b
- /// </summary>
6 |% n* Q2 F6 r- f - public class Handler1 : IHttpHandler
, v4 f0 w) v7 v- G5 d# @& Y - {: h2 \9 e; f2 b' x6 X
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池; h, w; _' u3 Y! P; |* ~
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池$ s t2 x* y1 Z
- public void ProcessRequest(HttpContext context)
( L6 ]' r! z, u$ b! x( h# R - {
! x. Y7 x. H5 V8 P( ]' Y3 r! e - //context.Response.ContentType = "text/plain";
7 C0 p/ V3 V S8 i - //context.Response.Write("Hello World");
- U# P3 E, |# [9 R Y9 {4 i - if (context.IsWebSocketRequest)
2 c3 _1 V# a- b) q - {
! a: W& ]5 H9 C, ?& }. y - context.AcceptWebSocketRequest(ProcessChat);* p0 Y- J% [! K; ~ Q
- }
# T& Z+ X* @; `- X+ j% ~3 u - }% C, F- `8 P. \9 ^, ^/ M
9 A# d6 ]5 D' b0 @1 i4 v- private async Task ProcessChat(AspNetWebSocketContext context)
Y; U6 l+ Z" m3 ? - {: |# Q* s, S, m* [7 C5 f5 ]
- WebSocket socket = context.WebSocket;! {% e& n B( E1 H
- string user = context.QueryString["user"].ToString();6 A0 i) i6 p) g$ z5 E4 J0 r# U% p% V
, w9 N, J0 T5 p& r& F2 i. } j- try
( I. v# e. f- x8 U* V" K X. ^9 E - {# j/ U1 o! R% b* h. v
- #region 用户添加连接池
8 \8 z& ^% O* O6 ~# J* M; p7 _ - //第一次open时,添加到连接池中) _, Y- ^$ U1 e8 E. R" ] V
- if (!CONNECT_POOL.ContainsKey(user))% ^3 C% S- U" q% c
- CONNECT_POOL.Add(user, socket);//不存在,添加
M2 M. T7 K9 u - else
2 N0 Q, c& G I/ J - if (socket != CONNECT_POOL[user])//当前对象不一致,更新5 @, \* o! j" U& m' K0 Y& s
- CONNECT_POOL[user] = socket; C% P5 Y+ C/ }# @
- #endregion
8 m8 R& I( u1 ` - ; k0 j( b' A; R3 P9 J
- #region 离线消息处理- G9 {2 ]) R* n/ {+ _
- if (MESSAGE_POOL.ContainsKey(user)) S4 l: O6 I- w3 {( \3 p* l
- {6 C3 R$ R( R0 u0 q! p
- List<MessageInfo> msgs = MESSAGE_POOL[user];0 ~- A) N0 d& U1 I
- foreach (MessageInfo item in msgs)$ P0 d; d4 i0 b8 R' r4 h
- {( W; V3 \ x! o4 r# y
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
( R9 V: ^+ y, n9 M - }
2 Y% l' ?" G1 A/ C4 y; }) h - MESSAGE_POOL.Remove(user);//移除离线消息* s! C3 h6 T. k# \) D/ o6 R4 [
- }
7 T) K" K# ]: u g; V2 T' C* N( f - #endregion
\! x, S8 L B y/ P3 h
5 ^8 [( \/ M* H. X4 E) M- string descUser = string.Empty;//目的用户 P2 |& `6 Z$ ?4 J3 q
- while (true)- L7 Y0 q' T A$ [, Z
- {9 X+ ]9 s7 |3 o
- if (socket.State == WebSocketState.Open)! r* e! B" z: h, |! d
- {! ~) `- J. Y. ^% h* X9 u y' j
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);; F: A6 J" N0 b4 y
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);$ g7 I8 R) j6 @& J
9 v( ~* t8 j+ |2 ~1 m$ s- #region 消息处理(字符截取、消息转发)) U: o5 v: n0 l8 I; D
- try
: z. n1 V6 j0 ^# A1 o7 h7 T3 u - {/ D* \4 j. @. J2 Q5 ^
- #region 关闭Socket处理,删除连接池
+ g2 C4 I) k0 ~; t) [$ o5 ?! A: u' ?3 q - if (socket.State != WebSocketState.Open)//连接关闭& ]' T' [# b* h4 a1 g; P. f
- {
& [8 l% S" K0 O" F0 }3 Y I5 v - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池$ z" J5 c/ Z% A7 \1 ~
- break;
& q* E# ]1 f, s9 S# A0 M - }
* i( y: ~7 k$ x# ^1 q - #endregion4 A. k- i/ H1 x& {' l+ \% j* U. [
- " v7 L5 f6 S' b9 X' o/ P1 I# L/ t4 S
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息+ Y$ H. n/ ?' X7 v
- string[] msgList = userMsg.Split('|');9 x- ]3 m; F8 \$ H" d7 L6 z
- if (msgList.Length == 2)4 s `7 k( b3 A h. Q
- {
3 ^. h- j! q* l2 \# X2 k - if (msgList[0].Trim().Length > 0)
# m; l3 E" n! [: I! Z( k - descUser = msgList[0].Trim();//记录消息目的用户
3 {8 J$ |* j* [& \9 Y, e, X) b - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
2 V$ r5 `% n; ]1 e2 c) V - }
7 }$ z, m% p, v: k - else/ q9 \2 t% h' v: K k: h
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));$ I2 d0 {; x" r& e [7 i i4 T% R
$ ^+ X# w2 l' v$ Z* e: V4 N- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线7 A/ r. R3 o1 _+ R7 B- f0 ~- ~
- { F" T" x8 t- U& K: N
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
. ]5 V# t Q; n9 L7 y. L3 ? - if (destSocket != null && destSocket.State == WebSocketState.Open) E2 [! M* E6 e# @
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);, r8 y# Y- o; m5 j! ~" T
- }
$ f# h! z0 b# R7 i7 \$ c5 E+ F/ t - else* L% D9 b% |, j$ t$ |; Z7 P9 z
- {0 C- L: m/ ^1 c5 g& K4 x
- Task.Run(() =>/ m& e0 ~$ Z/ y/ S
- {' E. O9 W8 D# V8 t6 b, ~9 G* W1 b
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中1 O1 W: y$ f% }6 B9 X
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
- J/ Z" x1 v) C - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
?1 Q1 T1 s9 a1 p. t/ x - });
1 i, U. D7 b% _& _7 P - }6 p1 C9 n/ G2 j* z; |1 r( [. G
- }0 T3 _% K; w1 t+ {
- catch (Exception exs)
% r: N3 a h, c5 V; F - {
) G9 @9 v- G. _) j7 R6 E - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
) ~2 L0 x* y% W4 V - }. }! c |! e4 ^8 A: K
- #endregion
4 B' A! P' ]: x - }( h+ K3 A K! M2 u) ^/ X& l
- else x- v/ u f& K) @. o
- {5 N+ U/ ?# x! w$ h( o! ^
- break;
+ [$ l3 g3 w2 k - }( Q& V1 I# ?. w0 Q
- }//while end
: q) r$ } `* F4 h6 u6 `' R2 M - }
+ U/ C" @3 ?9 f1 Y - catch (Exception ex)- H% L: J1 _ {' x
- {" \7 S& t s/ N2 S: `9 [
- //整体异常处理% F7 d! Q% Z3 v9 ~# W @; I5 U, t4 q
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
: B: k1 g, U4 G! }8 k5 N. P6 m - }
) y! L# G4 }( }2 u/ S, X0 r - }
7 x$ n6 f0 D6 @$ u- y+ Y
3 f) b% Q' }5 e. h6 o* u; J' s; |- 5 E! `* N! r7 z6 W- w3 T
- public bool IsReusable8 u4 P- F" N& Q& }
- {2 ]: X6 g6 e" C4 m9 c7 e
- get5 N5 z5 h l- q% U. a0 `5 E5 X
- {
5 C: w1 j$ D* b- H4 _ P - return false;
' P d/ w9 C* [0 M - }1 z, D1 D! O/ n f& ?! ~% b% [
- }
- y' B# m4 H3 [- s: V - }5 L! K8 S1 b9 y, V
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
$ O6 T* g- G$ M7 ?9 A! m |