服务器端代码编写 1.新建一个ASP.net Web MVC5项目
* {- u/ f4 w! U2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
+ g K* x: n$ R& o7 X1 a4 H - using System.Collections.Generic;
% {6 B& M- ?+ w8 x+ _ e) W3 h3 t2 D( D - using System.Linq;3 M1 u" x: k3 \- q" `
- using System.Net.WebSockets;3 p4 O9 @* r8 I: F
- using System.Text;7 L) @2 I; b& p: _% g1 Q5 A! i; o
- using System.Threading;
8 B+ H+ j& V0 `. w; X& B% p, Y - using System.Threading.Tasks;/ n0 Y( o! d S% r* g# g3 ]1 J
- using System.Web;+ t2 { F& v- J* J- h- ^
- using System.Web.WebSockets;' O1 U, b6 C( l, U4 k
- + T" B- G3 l: n0 ?) y6 b
- % Y# a* Z" F6 U' D i
- namespace WebApplicationWebsocketHandler
. i. _/ y" e. g6 G) z3 o+ Y! O - {
: C2 t3 R+ ]1 s - /// <summary>
/ b4 r# i `$ v% z- r3 v, i- d6 N - /// 离线消息
! j" Z# J) K G8 a - /// </summary>
. X- g$ N$ j& u/ a. A) n9 W6 [8 R; ~ - public class MessageInfo" s6 Q0 ?; s; |/ y! [2 G7 B
- {! _; [% i* |- T
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)$ r# a8 {) V B
- {- p% z2 q* n) K0 g! P
- MsgTime = _MsgTime;$ W7 _5 T7 C5 L) M- Q
- MsgContent = _MsgContent;: i3 J2 M" C5 h
- }8 e- e. i+ M) ~+ \! Y9 W
- public DateTime MsgTime { get; set; }
! _% U) y8 R% @ - public ArraySegment<byte> MsgContent { get; set; }
3 |( f3 ~& i+ N; k" b - }' r1 ]; B- l/ B5 n5 {: n6 |
3 z- f" o" M, m! t- Y& J$ L
/ ^9 _( ~7 O! J0 X; e- 3 y+ p8 a6 c9 E9 }; t
- 4 V4 j+ s! N. V# Q4 K. i3 Y
- /// <summary>
0 _8 F* f7 ~% T! Y - /// Handler1 的摘要说明7 I" v& z: ?+ W; _! i, s
- /// </summary>3 U2 A* f6 R; ~ f3 l
- public class Handler1 : IHttpHandler
" e9 F- O3 ~: M/ ?: Z0 h- v9 a - {" J1 C$ R* a4 m* h; k8 ]2 _- }6 U
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池2 ` {- r6 e$ S" ], o) ~- @! X
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池% a# P- Q4 B% | J
- public void ProcessRequest(HttpContext context)# C; A) z( X2 P+ X8 b- V
- {
6 a* y8 ^' E$ h# |# x) J - //context.Response.ContentType = "text/plain";
0 [1 I6 t! z* ]$ k# ~' B0 B8 o - //context.Response.Write("Hello World");' t/ Y% I8 r4 i, @, l. P
- if (context.IsWebSocketRequest)
3 C2 Y! K, ?6 e$ V& c" L+ M3 P - {
% |2 D# m/ I3 S- y0 ? - context.AcceptWebSocketRequest(ProcessChat);
9 W# i; U8 B5 K/ N+ b - } " p U+ H( k) C2 d4 [
- }7 e5 G( B9 n5 P; c0 Z
+ H) i9 W+ R8 I- private async Task ProcessChat(AspNetWebSocketContext context)) b4 s' X8 o% l5 ^
- {3 J& o4 A7 a4 M# ^: g- E! T
- WebSocket socket = context.WebSocket;* S b2 \' a3 _, X
- string user = context.QueryString["user"].ToString();$ [6 A8 W; z* |# r/ r( D5 H4 E- N
- ( ~& ^& c$ p! M
- try2 H+ S% T @) A y" h
- {
) T7 N2 {; g- |2 `7 ~. S) t - #region 用户添加连接池
2 n7 f2 ]8 v% M* e; \+ S - //第一次open时,添加到连接池中
1 o$ v3 d. B+ |! J1 U2 A - if (!CONNECT_POOL.ContainsKey(user))' s- g# U" c+ h; z4 _7 ^
- CONNECT_POOL.Add(user, socket);//不存在,添加& j+ i9 j! t2 {2 h, _
- else
! X+ ^9 F% U& v. ] - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
) l& J4 c, O7 @6 Z1 H# }+ X - CONNECT_POOL[user] = socket;
% s ]3 l- z" K! @ - #endregion
8 | n. u+ t1 Q3 A5 J% v$ S
5 T7 l( P: l! j7 k' p- g- #region 离线消息处理' ]8 X: _" W( ^& b
- if (MESSAGE_POOL.ContainsKey(user))
/ p) J7 v1 }0 c6 D - {
/ E, M5 ]0 R/ u4 n) g - List<MessageInfo> msgs = MESSAGE_POOL[user];4 x3 Q f2 C0 S7 A
- foreach (MessageInfo item in msgs)% v2 C( Y) L0 f( |/ [8 T1 ?
- {! V& C! h6 g/ \% q( H% G: n
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
: F, v$ |! C' K* g - }
4 i* R: u* t/ z& |9 b' g; ~ - MESSAGE_POOL.Remove(user);//移除离线消息
) v$ d# B5 V; Z0 h! A - }2 w0 p& I m* V l; I' V
- #endregion4 i8 a; |. S' |2 o5 z9 v4 G
* _; p9 q9 K1 K) H) j; q S/ I- string descUser = string.Empty;//目的用户
6 V" t1 \: C0 @$ v- a - while (true)
! x* n/ Q) n9 o8 L* e: L - {1 h, D( u/ u1 Q, u$ f* Z _
- if (socket.State == WebSocketState.Open)
; Z5 ~8 a4 d- ]* Z c! | - {4 L6 _% w/ P9 h# y$ o/ @& [2 I
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);5 W; Z5 o$ O1 G9 M
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);1 a9 r- y l' L; \# t- D# s/ j, @2 K
; S3 J4 Q c, Z9 j- #region 消息处理(字符截取、消息转发)
' h ^* G: b, r - try: t) g6 n6 z( y( t7 e5 @
- {% h: s# N% w& @. P( n
- #region 关闭Socket处理,删除连接池
7 g2 F$ H7 G- [9 Z( r9 ?6 h p# Q+ n* v - if (socket.State != WebSocketState.Open)//连接关闭
; B& E* y0 Y, b$ g - {. [$ v2 S& X3 f+ n$ g9 ?
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
( Q0 T( L7 G0 {4 H# O P - break;; R! a# K$ Z% P( m& L1 I/ f' h
- }/ P7 u' g/ Q6 f, N' l- Z3 I
- #endregion2 _0 }8 D e, ^
" S1 |' L- C& f: d" A% S J- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
& g. W. i0 \$ B. i5 f8 a - string[] msgList = userMsg.Split('|');
e- z. d4 g8 Y1 \9 J' b - if (msgList.Length == 2)
$ _; K, e- Z( A$ |5 w9 F5 K: \6 e" L4 t - {# c$ ]" ]+ {- C! a
- if (msgList[0].Trim().Length > 0)4 v; P1 }8 D3 l3 L {4 F
- descUser = msgList[0].Trim();//记录消息目的用户
, f; O8 Y; g' Y- }% m# c1 w$ c - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
2 v+ w' D/ a( d2 t1 c1 c - }& i+ [4 C: u! z3 i+ G x5 W5 N
- else0 |# u. n4 [1 J3 x
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));. @$ Z. U4 X% W
- , T; p8 D) R) F6 t) H" e
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
; |. E1 s# s3 i' N. y - {4 N! L. W3 k0 Z; i% u4 n6 a X
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
7 x6 A9 d. ~1 J, a; b/ O$ Q - if (destSocket != null && destSocket.State == WebSocketState.Open)
8 `5 K3 ]! [9 q9 |, G: @! M9 @ - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);4 h3 `3 ]2 F. ?' D/ D! V+ K7 k+ _! l
- }
% J6 v _# m7 ^% s g" Z5 R - else0 g1 i( a+ q5 j5 P6 n& X
- {. ?& v/ I, M! G3 ^8 w. d9 s
- Task.Run(() =>
; U& F1 B2 u* p/ v* b - {
9 r* `. i! C( J9 H% h6 S - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中3 s& T) @9 H6 ]" w8 D# I
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
9 ]5 \; U/ t+ b) c0 a0 W: W - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息% R$ E4 }+ w7 i$ K: q
- });
3 o- j3 i0 z F: H* A! m - }" b# x7 _+ ]: F p- O' b
- }) ~# t) ]; x: P* W! ~0 i
- catch (Exception exs)
0 t# \! Z" `0 Q5 S v - {/ b/ V0 Z( I1 _. ~0 g* V* s7 L
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息' S B: o& c% [4 O( C; @2 w2 u
- }
- X' x2 O. e$ C) {, @% @7 [5 J1 @ - #endregion" B' g. z1 F5 X
- }$ r" P; T, U% y5 }# [# Q
- else
# o: [6 M5 r @2 ^/ f/ w - {
$ F9 A* L! e( u9 V k9 b - break;2 f0 l7 y9 _9 p8 y9 u# C5 M% K- b e
- }! r/ g1 ^ h A1 f4 D
- }//while end
# K. K9 @! y. g v$ L$ Z9 X& V* F - }
: p0 I4 C! h( Q' Q - catch (Exception ex)
# S* z* j8 q) Y5 q5 Y) z9 \ Z - {% t: o9 b- B' d+ L: R0 w- g& r
- //整体异常处理
! `/ W/ W- E6 m) o- d* U* h9 G - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);- x& G$ Z* }/ T9 i" P' C. J
- }
* w; T( e( I4 t. A - }4 P- w x* I% ]
- 9 ~: i5 j- `3 i" h
% v7 Y# w5 P1 h1 f8 x5 i- public bool IsReusable
* t: @" H' p" ~ - {
0 s- Y5 t; } B3 T& }8 L - get, T5 R" E. F2 ?/ w, e/ |
- {
9 U, S( u3 s0 C' U* g4 e. z - return false;
0 q% }; S6 K6 I( D* ]9 W. Y- j5 R - }0 E8 |9 h* r( u T
- }
; d" t0 D( q' `7 w( p& j - }
0 p& a- l* P( K8 H. c - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 & X3 z V! Q3 T" D5 H
|