服务器端代码编写 1.新建一个ASP.net Web MVC5项目
G7 Y5 E( Q, q7 l! r2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;6 [ u" y2 K$ K
- using System.Collections.Generic;/ {; @6 P; m. u( q7 \1 }7 A
- using System.Linq;$ w. d# M. Y3 \5 L- v8 ^
- using System.Net.WebSockets;
5 Y& s8 _$ ~! B: a' v y - using System.Text;
5 H% H4 n3 ?, P* U - using System.Threading;* m6 q( ]7 x4 |& J$ b+ X: Q
- using System.Threading.Tasks;4 V" E$ f, |# q v9 C' n% Q
- using System.Web;* x; e0 B7 Y' h3 ?# r
- using System.Web.WebSockets;5 Z1 ~% o2 p6 e# W
# l! {) G/ A2 q# X) X
5 X1 s$ L& S5 F9 r3 l, ?0 l$ A- namespace WebApplicationWebsocketHandler
8 n, S2 K: z; U0 ~) V - {% m% ^9 {( {( d
- /// <summary>
7 T8 X) J: K4 p# l7 |/ G2 Z$ o - /// 离线消息! L4 f, ? ?+ j& y4 I- o* N
- /// </summary>+ |4 |* z+ X6 V- F$ O
- public class MessageInfo
: T" A1 H1 ^9 { - {
$ X0 t1 r* u l9 Q3 h4 Q4 e1 ^ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
1 l7 |: y. C, Y7 Y1 b7 T - {
# m6 {. p/ }# v: s# b7 Y - MsgTime = _MsgTime;
0 G3 U5 h3 o3 T/ X3 o - MsgContent = _MsgContent;
* b: g( m# @2 E0 ]1 { - }1 n. B5 F( F' Q7 |) e: z+ _- m" Y
- public DateTime MsgTime { get; set; }
3 B; z, e$ n1 t5 `& y- [$ R# B - public ArraySegment<byte> MsgContent { get; set; }) [! n$ u Y5 D7 P0 _
- }1 I: f/ L% g. ?3 I, f0 f* C3 j
7 i; q, L% ?6 s. O' q# v$ _( b( e
) I7 u! B5 ~; y5 g4 h, w
1 Z3 j( \# @+ R' x! g/ Y
2 p0 T+ C8 y* u f8 v- /// <summary>' }( `1 ~" ?$ x$ s6 A6 E6 \) D
- /// Handler1 的摘要说明
$ ]2 O9 r o3 H7 p - /// </summary>2 I( G; r2 f9 ]( S) }
- public class Handler1 : IHttpHandler
$ S+ g" h$ Q! G - {
9 A% |- w8 G) Z - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池6 j( F2 l% z% R1 H/ e+ D7 G) }
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池, k+ h: q2 ]' E
- public void ProcessRequest(HttpContext context); n) }8 Y* b- k0 E4 T
- {
5 L! @( A) p5 n! ] - //context.Response.ContentType = "text/plain";
1 N, R) k# B* J1 H( a8 b - //context.Response.Write("Hello World");6 Q0 s8 U0 f+ a. z6 i
- if (context.IsWebSocketRequest)' z' \1 {; A5 ^/ l2 b; G6 p
- {
$ D# O, u; M3 J, h3 g7 O - context.AcceptWebSocketRequest(ProcessChat);
" w8 Q' b% ?" Z6 z& i) \ - } ( j! i+ u2 O/ S9 ?
- }
$ a/ e6 f( a/ w - - _0 j8 S" U9 p5 o' b) J! q
- private async Task ProcessChat(AspNetWebSocketContext context)
1 C2 t1 p2 H9 {1 K5 U' @ - {+ L4 v9 U" t/ \
- WebSocket socket = context.WebSocket;
3 X( l2 P& J7 y1 n9 M# a - string user = context.QueryString["user"].ToString();
1 |, v7 F+ G, V* i! i" @) O
7 H |! h: V' _7 m+ i- try
& `, v& E$ n4 B- f - {
$ M* Q- R/ i! f- L6 j! R- G) j4 ? - #region 用户添加连接池
5 @! k8 A" T# f - //第一次open时,添加到连接池中8 T, \: Z' a. B0 X$ Q' S/ U: {( j# A
- if (!CONNECT_POOL.ContainsKey(user))
" c9 H4 j% d+ _4 b- d5 p - CONNECT_POOL.Add(user, socket);//不存在,添加- D. T$ k+ O9 d- ~& Z7 R7 @0 P
- else
/ W6 d2 k. V2 c8 h4 ]5 k( e6 W - if (socket != CONNECT_POOL[user])//当前对象不一致,更新% Y0 p) X/ l! p# r/ y3 L
- CONNECT_POOL[user] = socket;' H5 E, R& B2 m7 H$ ^) N
- #endregion! }# @. \+ v+ K, z! X! y% v( \' }
6 v- S$ }4 b% d p8 f* J$ f- #region 离线消息处理
0 g% t/ Q8 q: N - if (MESSAGE_POOL.ContainsKey(user)). t+ H7 o: R, S: q6 ]2 Z9 [
- {
) w/ K: C/ @# g6 t - List<MessageInfo> msgs = MESSAGE_POOL[user];0 w1 P) @8 b' r4 [
- foreach (MessageInfo item in msgs)
3 V2 X$ R7 C/ y" E+ f7 c - {% l: p) i* a' b8 |6 A+ i8 Z
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);, R' i2 L3 m5 O$ d7 N% ?
- }
7 X: R# [- A; f! B, x* ?0 p2 ^ - MESSAGE_POOL.Remove(user);//移除离线消息, l, Z9 C' o8 a9 e: _
- }/ {1 t) g; K" i+ O+ w0 G
- #endregion U# S5 y! o# [. U0 q- @4 A
; S8 C! u: k9 c: A1 N* z0 }# m- string descUser = string.Empty;//目的用户+ @: `+ s/ |$ [9 R
- while (true)& X, Q1 R4 E Z' c) @# a) s6 O! e
- {8 g0 N" ?* J4 `# `& n
- if (socket.State == WebSocketState.Open)
- X* ^: o, Z+ d z/ w4 R2 U: f - {; _1 J! G& Y! y, d/ b" \
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);+ l" P5 b) v; f" _% Y
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);, h4 W8 b' Q7 d0 `( f) {) E" q
# L {# ^. ]8 i/ k( c5 D- #region 消息处理(字符截取、消息转发)
8 j' |# r7 j/ e. X* h9 C1 d! M - try' o; l" Y' K1 u; G
- {
( F! J/ {1 m& X" Z! p y! K6 g - #region 关闭Socket处理,删除连接池
4 s; d$ I9 t$ [: \+ d - if (socket.State != WebSocketState.Open)//连接关闭) }8 q- @8 S3 q' ~6 V1 K8 b h
- {
( h7 ~7 t7 G$ h% C - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池' o! [& ?9 [; w% R1 K! U- Q
- break;2 x2 |. H! \) n
- }0 q( \/ z6 D" R( V2 p3 u* I
- #endregion1 [/ i6 i# t' I3 Z2 w% Q0 Q
- 6 e. ]: O0 ], A( w1 R. F8 A
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息1 `* J" n, @3 f% r
- string[] msgList = userMsg.Split('|');. m- z% ~7 I, P( a* h- O
- if (msgList.Length == 2)
* [. }+ U" k3 j1 N$ Q - {
$ O: U" m, ~+ O; {, x5 s$ L - if (msgList[0].Trim().Length > 0)" R. u) k1 j/ P/ G
- descUser = msgList[0].Trim();//记录消息目的用户2 @( q1 F1 t8 ]
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
8 D" l; P! X) s' ` - }
4 R0 T: C \5 h% ^9 V* F - else$ I' b4 f; P* }
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));- T1 ~4 Z9 k @2 s
( @* ?* B+ W6 @ g" S# v E* N! t- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
0 ^0 H. ~: w7 z1 I - {
1 V, |# K# s7 Y( c2 K - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
& t8 D1 v* B [5 i' {. f4 S! Y4 G - if (destSocket != null && destSocket.State == WebSocketState.Open)2 b+ @1 s! R% h
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
7 i8 J9 E& ?: {+ z( y - }
% ^2 T6 F6 L, B* ?/ t- x6 f - else
% A4 L7 ~9 Q3 e( w$ { - {
2 ?& [+ v3 h6 T1 F8 q0 P( U6 p7 Y" J% ` - Task.Run(() =>( t" z3 X. s4 n+ U1 v; U, z
- {* S. y$ c' R. F; h7 R
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
3 {) o: Y3 Y& E, d) g4 U - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
z2 t- H% v; l! h- ` - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息& F: B' z2 m, j4 L% s1 L! P1 K7 |
- });
& @; p8 D& v7 `7 O - }$ j5 I" k0 v2 {1 _' A& P
- }. ~, ~8 a) @5 N K7 ?7 O6 J
- catch (Exception exs)
) {) ?5 y$ m% k) I- Q! `8 X - {
, [& h$ _" d2 l! q! b - //消息转发异常处理,本次消息忽略 继续监听接下来的消息; L# h2 F3 E! l# J" f: K) v
- } Q0 `% c$ ]0 c4 O3 T+ ~- E
- #endregion8 X$ ]0 j" l: W$ A$ T; \
- }
: v& ?* j1 w; I x" }) q - else
7 s+ s H3 y7 R# e5 ^ - {5 G( D5 F4 S$ l* N' C2 N
- break;) T$ b5 |0 A/ R% T
- }
0 }' W8 n* e. f9 T; Y& X - }//while end7 C/ m$ d t& Q8 G$ ]
- }* x' ], v5 @$ U; Z8 j
- catch (Exception ex), T: _7 X* o9 r+ w# w+ S
- {
& B2 A: d; j' t! k- `/ \' W - //整体异常处理
% @, D, \# U' H, h( X4 o - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
$ r/ U7 L; K! G; f2 |( i" M - }
* w9 T9 y& c c2 b - }' h/ W* c% W/ c: B0 o
- 5 ]0 e4 R6 p' q0 Q9 O
- i3 M* E. [% b
- public bool IsReusable" v" B2 c( v& t4 w
- {$ u. ~5 o9 k9 c& w, v" X$ e
- get
+ _/ h- L5 c+ C; o$ E/ m - {
1 N- B/ K2 R& D# U& {# w7 }: T - return false;+ G+ l+ d' [3 s4 s
- }6 x1 @+ o. r; Z' E. t* Z/ @
- } L7 \/ ]$ ~9 T# [& B- Z! I
- }
& h* d# u" O/ N/ P8 S1 { - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
6 k6 u- j& N* Z1 g4 t |