|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 4 K2 R; o1 I. V
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
' v9 l- I/ ~( x! _ - using System.Collections.Generic;: d$ V. ^5 k$ I7 E6 D
- using System.Linq;
6 b8 a0 _% i4 F: B - using System.Net.WebSockets;
5 _: V, C7 N# y4 f: |9 A - using System.Text;: h# I; u/ H$ h9 b. n% o
- using System.Threading;
7 J' Y, G8 W0 }7 ~) V8 c3 W B - using System.Threading.Tasks;
1 X3 R9 W* B; Y - using System.Web;4 [$ R. Z% S) J+ ]8 f, O, X- n
- using System.Web.WebSockets;
0 @4 I1 W d b3 w& a
1 R+ w; h g$ x2 w w- K- ; W* k( T: g/ C6 S: ]( C
- namespace WebApplicationWebsocketHandler/ y; X- y5 Y% ~0 R) N
- {* ~" P) m$ X P2 @
- /// <summary>
# f5 j* `( @, D% O* {" d& E+ T2 Y - /// 离线消息
# p+ r" S* U) m) Y - /// </summary>
/ R/ t% s# c% e& |8 J6 R* l4 y7 e - public class MessageInfo
. q m; K! Z+ B3 O5 { - { _) K0 u$ g$ M& a" r& h
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
2 g- C- [! A' o0 x' u - {& l# o" _) ~1 m
- MsgTime = _MsgTime;
4 n! Y/ A* G/ K6 j2 y+ e5 u - MsgContent = _MsgContent;
6 O# g @6 c% _, G$ L# Y7 V - }7 `' f7 A; C$ D$ S2 Q$ g
- public DateTime MsgTime { get; set; }& n- o* T& y F* K9 c
- public ArraySegment<byte> MsgContent { get; set; }( O% z# r6 p8 |9 ]- g
- }
6 A7 f% Z) m$ u- U - 0 W. v2 @' s% n2 r. O# O: [
- 4 [* A: w* a4 j- D
- ! K9 z5 Q' k6 q* \8 R, g1 ?$ S- W
- 9 y, A2 b1 ]2 ^* p( P5 S
- /// <summary>9 p5 v7 _; G3 Q& e3 k0 ?
- /// Handler1 的摘要说明) z0 w1 @. P) c, b2 o3 j! G
- /// </summary>
5 B: O' \- O9 T: S+ y! R - public class Handler1 : IHttpHandler
1 a# y- |* k3 L0 C" e- S7 e/ _4 u - {
" M( k7 H, e; | - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
( `9 P- T& K1 Y7 C - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池- L: v0 y7 j# v% Z9 q3 R3 {* d
- public void ProcessRequest(HttpContext context)
4 C# Y& N0 [% h' r5 t6 w% M, H - {* Z; E7 q/ q6 j
- //context.Response.ContentType = "text/plain"; g* h2 d; [5 C$ E: L) K; |
- //context.Response.Write("Hello World");5 q2 f: s1 t) q- h& X1 Q4 q- v
- if (context.IsWebSocketRequest)
1 K( r6 \+ A# a) R- G( B; H: A' y% x- G - {/ ?" f" i% T" {1 D
- context.AcceptWebSocketRequest(ProcessChat);- ~1 \' R |) r
- } 6 p- N0 U( v t0 M- U
- }
p# M& ~ o$ r/ X0 X - ! x; R6 |3 `, B5 C3 L; Y
- private async Task ProcessChat(AspNetWebSocketContext context)
: E5 H/ [, e" N0 s1 a% @/ I - {
1 I+ D5 V& R- z; I! \# A - WebSocket socket = context.WebSocket;7 P) i$ e' Q( h/ i3 t4 F$ U6 p
- string user = context.QueryString["user"].ToString();
& V P$ C6 C+ K2 j% O9 r% ?9 G- L- G, ]8 j - * c) r$ q0 U8 s
- try
* r2 D# l/ l6 N. x; j - {
+ i: }$ ~# p4 @; ]8 G - #region 用户添加连接池6 R6 K- o& r5 n- e4 B" \' P
- //第一次open时,添加到连接池中! \4 ~! Z# \: y7 b6 w
- if (!CONNECT_POOL.ContainsKey(user))
$ |5 W& _' r! U# U7 q; u# o - CONNECT_POOL.Add(user, socket);//不存在,添加
# \. Y% r% @- f - else
) R6 J1 M, n9 o0 c0 m6 x0 M; q- S - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
* M" J2 ?4 V' {, s! B1 s3 ^ - CONNECT_POOL[user] = socket;+ m; q) k# h0 ]# ~# D3 O
- #endregion% A" f" b8 {+ M: O1 ^1 V
0 A2 N2 n& o9 s4 B- #region 离线消息处理
* A% P8 B2 Y" j" z+ W; ^ - if (MESSAGE_POOL.ContainsKey(user))- L& A" a3 n3 V. ^) T
- {, S" E, G6 V* f& T
- List<MessageInfo> msgs = MESSAGE_POOL[user];
; S9 L2 H8 _! w5 @ - foreach (MessageInfo item in msgs)* C3 S0 t% |' A& ?
- {
3 Z9 F ^' B4 G* T - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
+ [) j( h% O5 h! ~: d/ c! j* t& R - }+ y1 D e7 m: h6 }
- MESSAGE_POOL.Remove(user);//移除离线消息
$ i4 J3 D9 v1 ^. n$ S/ v/ f$ H - }
8 X0 [0 K4 C8 n! n2 ^ - #endregion
7 Q* D& B& V0 _3 _ - / X C# B( M! _# F& I8 y. x
- string descUser = string.Empty;//目的用户% W9 d3 k; [( ?. A7 A1 o$ ?
- while (true)
% y q/ o- _. M+ C$ e7 L5 U - {
2 @; p$ D3 y1 K: U - if (socket.State == WebSocketState.Open)
) [$ A W, B) _ - {' b+ ^, b+ g2 W
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);- v o9 ?7 d6 \' S: h
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
% ]; W( L9 {$ v
/ m3 D( X9 Q7 J4 N3 P+ d2 O5 S0 J: e- #region 消息处理(字符截取、消息转发)
3 R1 D' \2 S+ C% @/ [" e, d - try. }5 u4 T: U" j! `
- {! Y! F' y- k, n/ t' j6 U' h5 F/ \4 C
- #region 关闭Socket处理,删除连接池2 }' B( l3 f& Y$ [3 b
- if (socket.State != WebSocketState.Open)//连接关闭
6 e, j! K3 ~6 P - {
J# ]; `1 D) D1 D - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
8 N+ }* W4 _! p: W - break;
0 [$ H6 d' R) K8 E+ o4 y; @+ d6 ^0 q - }
! e8 _) R% l/ o9 m4 \1 x W - #endregion
& ~# ~8 D' }/ g# `% ? - ! d' U5 ^: h9 a$ A
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
! q2 C1 t+ w, I- V' {" X - string[] msgList = userMsg.Split('|');
4 ?9 N! Y# e8 m: S - if (msgList.Length == 2)& P; P" l" y9 P. v( F
- {
A9 h& K1 Q# x) ] a- ] - if (msgList[0].Trim().Length > 0)
" E6 Y* f0 f( x, t a+ j8 H/ C* D0 G$ V - descUser = msgList[0].Trim();//记录消息目的用户
2 }4 m$ v5 S' d: K - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
- L6 D" b; ^. p# A3 D - }4 N# w# c7 G0 f4 A; [: y9 l3 i
- else
: a: s- {' s/ O3 b L - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
. o; ~, ?0 M& e/ ~- e% B - ' V' w# v* v. h& l/ F! ~+ s3 v) C
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线8 @9 H5 A. A5 @7 D) z2 R
- {# b" A0 v# s/ D. @
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
9 W" q& [1 |; V- h. X( L1 i# L) c& \ - if (destSocket != null && destSocket.State == WebSocketState.Open)
0 ~: p, k. a' G/ B6 ~ - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
: ?4 I Z# i' {% L) i - }$ b" J* F4 f& X3 E9 O. a! E% I M
- else. v; j7 _/ S) V* i
- {
* P1 b. e' M$ Q1 Q9 q - Task.Run(() =>8 |0 Q+ p) G- T! x, l
- {# P$ E; p5 ?6 }% l0 [( b
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中: `4 e* P" R/ I# o+ [5 \
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());0 Y+ X4 a- l7 C/ I* ]+ t1 z
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息3 i: N3 i' [& x2 ?1 `' C) O$ {
- });
5 y, e) T: N8 z - }
z. G j, m2 N+ K7 { - }1 q- l% n: G" N& i
- catch (Exception exs)
+ d0 P* B; k4 o9 n - {
, ^; [2 C' G: { - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
! T! H# E" x: a1 y) `0 w) s - }
1 z3 Y# O" n U8 S - #endregion
: d) D7 v2 E! g% }# T' k& j - }) y) ~2 P; H6 X. t# z1 Q
- else
5 @2 D% D( f2 w - {6 r4 b" Q) [' N3 h0 x
- break;
% ]8 v4 ] I" ~# ]# r4 A - }
0 `& f( p! v; v3 ^8 d - }//while end
2 D! T. I$ _6 s8 e& V, p - }2 Y$ a% f% n& D; \1 n- ^- \( r
- catch (Exception ex)$ v9 }+ O. u& A6 {8 x0 P
- {, }2 U. {# N5 R+ q
- //整体异常处理. c5 | `% @$ \3 n: s
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
- s, M, u. x* p' [ - }/ @1 @7 A: L5 t$ [9 K! v
- }
+ m1 A. h4 Q0 C% K- e& ` - 3 i, ^% Z5 I/ c
- # s6 A$ g1 b, s2 [* a
- public bool IsReusable
) |3 F2 B$ K; | - {
, L/ p! q; ~+ A, e* j( I! f" U) C6 t - get( D1 e1 U! a7 q- }2 o; \1 m
- {
9 R# D2 E+ m& M2 t: w# O - return false;. _2 s8 O( Z8 W9 q$ } x7 P3 D: v
- }" T" h+ {- o4 Z/ ^# D4 ~- S3 N
- }: j5 ?7 v" O* E& |
- }
/ B8 J( F' e4 n - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 ( ]" o- y3 J; V1 i' D
|