|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 & x4 M( r5 ^& `
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
: g2 D" n$ ^& J- m6 k - using System.Collections.Generic;% S1 g8 w t2 Y" l# F7 ^: F
- using System.Linq;
4 D; r( |' B4 E- D - using System.Net.WebSockets;
7 A; e1 K! g+ @% `: k - using System.Text;
, l, J& Y: y: c - using System.Threading;
/ j/ z, S& G# @* ]( {: ]: X- k - using System.Threading.Tasks;+ W4 K1 a Q7 S& }& y9 c
- using System.Web;5 |/ t, f; ?1 p6 B" s& h9 z- ^
- using System.Web.WebSockets;
0 f$ I7 B% u: x$ o, {% K& h; h
6 c4 |4 G7 R; f- ( H2 ?/ ~/ B+ u5 a
- namespace WebApplicationWebsocketHandler
( b* h, L) d, R - { x4 ]' o4 B/ M" b# y$ M; m+ V
- /// <summary>
# G/ {7 h9 J& B) a1 T( p - /// 离线消息
6 ^ b% I" o9 E* r6 T: [ - /// </summary>
+ w# |. o8 p3 T1 | - public class MessageInfo
0 J' r- L% ~8 _: o3 G0 z5 z; G - {
; c/ b4 n9 E# ]3 J - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)$ |6 r3 ~, e' ?5 l5 J5 |0 @
- {$ ]7 {# N2 }+ |3 F B2 k# K
- MsgTime = _MsgTime;1 l! c/ M7 j$ ]9 y% d
- MsgContent = _MsgContent;6 e( i, ?- Q8 \0 D1 Y9 ?: I
- }
3 v' _& H# u j - public DateTime MsgTime { get; set; }
7 B. P1 f2 k6 p- C9 Y2 ]. H- K - public ArraySegment<byte> MsgContent { get; set; }: k8 r7 D. u5 D! \9 w
- }/ }1 F9 Y) h9 x+ G7 {
- ' A X* Q7 l$ l$ T( j) w7 x" K
1 [1 `/ B- j; ]- * o) X1 x, q, U' K8 N" }2 ], g
- 3 a$ E* k1 g) Y3 g$ I- ~
- /// <summary>' L; z, [- |( J* j6 R' h
- /// Handler1 的摘要说明' l1 B/ }! A! n1 Y
- /// </summary>6 T4 _( J4 v9 q; V8 K6 q
- public class Handler1 : IHttpHandler/ h, A( T" c$ x4 [) W9 |5 \; i
- {
) _2 e* T4 P4 v5 Z: ^ - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
8 }( w0 Z3 E3 z s - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池" `' P0 j4 O+ @& B2 c
- public void ProcessRequest(HttpContext context)
! h$ X4 L- O6 Q; p - {1 r( G# C% G+ D" ^* `! z7 R
- //context.Response.ContentType = "text/plain";8 p$ P V9 V5 g
- //context.Response.Write("Hello World");
8 W6 k: s1 Y5 k8 R - if (context.IsWebSocketRequest)1 ^3 u5 k9 l% |, \2 v# b1 c
- {; o, A9 C% X: c5 U, x* z; s
- context.AcceptWebSocketRequest(ProcessChat);( Y/ @& c1 ~- ~) e! x8 u
- } 3 I. | K9 q( F
- }
; d J5 a. }: K - 6 n' [, m' N4 S
- private async Task ProcessChat(AspNetWebSocketContext context)
; p: [& W+ H- N T - {
; D/ l R* Q% T - WebSocket socket = context.WebSocket;
& l6 b" j0 m x! D$ w0 U0 A9 O - string user = context.QueryString["user"].ToString();0 h3 {1 O( e1 j
- 9 R7 Q& c% S) ~
- try. F$ o. x* ~2 y
- {
8 C+ ]+ d. H4 l% [# _) P) k0 D - #region 用户添加连接池
5 b! i5 q& W @7 r& _ - //第一次open时,添加到连接池中" M: j/ k( B" M6 S. s2 f
- if (!CONNECT_POOL.ContainsKey(user))- @' O: e$ F. S1 `0 j$ |/ a: ]
- CONNECT_POOL.Add(user, socket);//不存在,添加
7 V5 D) S3 P9 |8 b- l6 u - else
( k% ?+ m/ e2 Y- R0 L7 B$ p" r# M; V - if (socket != CONNECT_POOL[user])//当前对象不一致,更新, p5 L1 I% R1 T% W2 O
- CONNECT_POOL[user] = socket;1 n. r5 {9 q- q9 g& M5 b
- #endregion
- S) N% H. w5 Z, Y6 p6 g/ j
/ ~% H- N% z8 j$ n- #region 离线消息处理
: `0 V- i% q# k% G9 G - if (MESSAGE_POOL.ContainsKey(user))! e& r1 z3 ]6 e) V4 Y# p
- {
2 ~. ^4 f# Y1 Q - List<MessageInfo> msgs = MESSAGE_POOL[user];
8 [- T# Y( N$ h4 u7 h - foreach (MessageInfo item in msgs). E* I! C! h) N: C% J
- {! B, t. @+ q5 f
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
, _' q" R1 s# X6 }- y1 A! O! L - }9 ~, e3 }8 K1 a5 W1 A1 i& Q: m
- MESSAGE_POOL.Remove(user);//移除离线消息
+ r3 M0 k; C: j- C9 d1 v2 C* q1 E - }
( Q( |/ B: l; y: C, h1 N - #endregion/ U$ n! G2 I; _% D
- " [$ }3 F2 X( z( z/ M1 x2 C7 z
- string descUser = string.Empty;//目的用户& w$ `" ^: Y5 |; ?; F
- while (true)- w& d8 v1 f6 N6 G' u+ M& @$ A
- {5 o9 x" ]" q# a) C- K& \
- if (socket.State == WebSocketState.Open)
, {2 E6 o% q- k( U' M - {
8 G: M3 L; ]; Z- h! s5 @! J - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
% t1 D' y* u9 C0 C$ M - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
6 Q8 ?. @8 ~ g) a
; L! l, d& d ^* L6 ]' }- #region 消息处理(字符截取、消息转发): i& b# q# M" v2 t x$ }
- try8 ?7 C; y1 V8 s7 N4 C0 i$ x9 v1 a
- {9 U4 \% K% B/ I
- #region 关闭Socket处理,删除连接池* B, D! n+ F' k
- if (socket.State != WebSocketState.Open)//连接关闭
" N4 s; d/ v" \ - {
6 O5 r! K/ T: R4 R - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
+ Q# a$ S* L0 w: H) a4 U& x - break; E( d$ L. G. c
- }
" F" c" o3 N, O3 p# ~8 P# M- J - #endregion
& C9 S' j, l) W- [1 s
# C) j* q3 D' i- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息; S; D6 s! ?5 Y8 M$ q
- string[] msgList = userMsg.Split('|');( k) W* \; A9 E
- if (msgList.Length == 2)
* d. t) G3 j3 ^1 _& I: _/ d - {" K+ j9 r7 @( Z1 u+ {# p' [
- if (msgList[0].Trim().Length > 0)' \- i% d5 N2 O0 _0 c: N h. N5 g" b
- descUser = msgList[0].Trim();//记录消息目的用户. C# g1 F% @, U/ S; H+ h2 q
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
2 m- i' X: v; d* _ - }
@$ _. ]6 v. }- s) I4 J4 e - else
& S7 D' h" m, T' m; c5 J+ x - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
# Q7 L# ]7 Q0 n# I - \& i: ?) K6 q/ K2 q# ^8 Z! ~
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
0 n4 r$ h. |: t4 x5 O - { X, P2 @& x: u
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
6 U+ U4 B% g' R" k8 h8 ~ - if (destSocket != null && destSocket.State == WebSocketState.Open); `8 D) n5 J- P) k" [
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);. r" o# i2 Y& ^2 S. I
- }
u! k( C3 I2 g; B: W - else
, j( @; C$ I9 O, b' ^! l; B; O - {2 e8 i. H. C! t! ?9 H
- Task.Run(() =>
9 Z1 d; {2 w7 v$ ^+ W - {& A3 s, S% P+ S' w3 T! y6 g5 i
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
) i) \ s# H0 t B x) }* X4 D - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());! `9 V0 j; w$ G$ b3 H
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
5 O6 }6 x+ ^0 L# V5 I# {! G$ ` - });" N6 u5 ~: f0 h6 T. b1 F# V: q
- }8 y" f4 p# h$ h0 ?
- }" `) ?% ^7 o# ]2 z( E/ h
- catch (Exception exs)
5 m4 w8 U0 c- Q9 s4 A. t" {: w - {
/ h0 S4 `7 o& ]! b - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
0 T" O# k' o7 |) z: W* u - }
: `! k9 B# P0 V7 M - #endregion5 R$ R$ Y$ y B: }" ]/ j
- }
2 }" J2 n6 S, \( b3 B' W) g - else
) g" |4 N4 o: Q& R( ~# f - { E+ B# S. l4 Q& i6 D$ ^: t
- break; {! K8 j! P, @6 r, e( Q
- }
/ l8 a+ \4 r9 @3 Q& W - }//while end
3 j5 V3 u# W5 _: J5 D+ {& W - }# ]) V/ E7 y5 K
- catch (Exception ex)" X/ i; |6 i5 y/ ` h: l
- {# v2 L7 w* D& P$ A
- //整体异常处理
, C5 i# U/ x7 H$ Q4 z - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
7 N$ z. a3 X5 _6 u: \+ x+ s: ~ - }3 ^3 R3 R6 I3 q0 T0 g+ B
- }
4 c$ `: ]) P' @/ h8 x" F
9 R2 z' U9 G9 E+ z$ }+ ^ i: e- 3 @! q& M; f/ V% V4 h0 k/ b4 e
- public bool IsReusable1 g) `& r2 U( j2 z7 [( ]% e
- {
# O) x. Y2 X _0 ?" | - get0 E6 d2 \+ H# @# G
- {# t: T6 d n5 b5 ~ G7 F
- return false;
& n. ~/ w- ~ ~ k. ^4 ~ - }* O$ i5 K; ~9 V6 F. _- x3 t
- }' M2 P y* A9 d2 ~; i+ i
- }0 x6 X, i7 Y( N6 {, b% ?
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
# Y9 `0 X1 c6 n% Q- H |