|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
/ E% s6 f' t$ @7 S1 N/ S: L/ ~& o2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
, n9 b1 }3 T, g9 P; d - using System.Collections.Generic;
2 D; J& D) L" y9 M ~ - using System.Linq;- J+ A Y' K/ X& D1 s! X' \6 y
- using System.Net.WebSockets;2 u( u0 q! K: I1 T9 b. c; q
- using System.Text;2 m9 |& L$ V7 E( p) r# _! s+ j2 \
- using System.Threading;' v! L2 ?+ Y) m; m# Z
- using System.Threading.Tasks;( |( b4 S1 J" k: T) S
- using System.Web;) U+ l2 g- q1 ?% C
- using System.Web.WebSockets;. @6 a# |( W- P
- ! E# X, k, P { ]- r6 f. ?
. _" E. b; [- [8 Q- namespace WebApplicationWebsocketHandler" t' Y2 E, c% w: U/ d
- {
$ g9 u' @ n+ [3 a0 L2 h - /// <summary>
6 y0 |; W' |3 z: V - /// 离线消息
$ C4 R) z7 D" R6 Q8 a" t) j - /// </summary>) t) k" d) k( i# v4 F) [) H
- public class MessageInfo
$ J6 }2 g1 g7 v' A$ F* F: [" z7 i+ _- L - {$ o3 k2 F T9 B# ?+ ]! b/ e, Y/ ]
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
0 J$ ?: o% d( g9 p9 I9 E# W - {
) W, d: E7 W- F+ P9 j - MsgTime = _MsgTime;
1 x: f! T: e! d! k5 s5 K& a - MsgContent = _MsgContent;5 ]' O2 H% S- P- m
- }
* c, i, u4 @5 } F1 q! y - public DateTime MsgTime { get; set; }- S7 L$ @! Q W" R X/ S
- public ArraySegment<byte> MsgContent { get; set; }# S6 g# M7 l; O( I: `
- }6 ~3 l& N5 ]3 i; o* L5 L, V8 h8 w
4 u- s5 C$ ]- ]) y# x- * a3 M+ L& x+ G1 e) k- \
- / D) ?" [- m$ j
- 4 z2 ~4 O6 x( N8 {
- /// <summary>
4 k$ E* z8 K2 c9 E1 @ H - /// Handler1 的摘要说明
: K1 d( z) s/ s( M6 }- d - /// </summary>
8 g' v* u* B2 Z5 O8 I& G - public class Handler1 : IHttpHandler8 f# N/ L. d8 R+ k5 P7 O3 g
- {
1 j( B7 S8 g9 U" S$ m( q9 K - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池3 d" @% e* b$ _) o+ N3 y ]
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池% p2 q+ h$ |3 A1 J2 t( z4 ?
- public void ProcessRequest(HttpContext context)& t0 q, ?- F# F) M: x( T5 E4 y
- {
1 F- A+ R4 E" w: L+ c4 y5 k" ^ - //context.Response.ContentType = "text/plain";
, p! \. g: L; r, G - //context.Response.Write("Hello World");
5 `9 g f3 R8 C/ J0 D- g8 l# w - if (context.IsWebSocketRequest)
4 c# K* X9 B# Z$ v. F) U* a - {
; g; x% |* w0 t - context.AcceptWebSocketRequest(ProcessChat);; @: ^# N* o% k3 V) {8 ?: P: f. l$ R
- } 8 s- X6 y- y' S+ C
- }
& F+ _* t4 u: X
# m2 D: b! B' d" |- I- private async Task ProcessChat(AspNetWebSocketContext context)8 a; i7 H3 s* m+ x, [6 l) h8 Z
- {1 r4 i. q% @2 |' C8 ~
- WebSocket socket = context.WebSocket;' j! B2 V( Z9 R5 z. I
- string user = context.QueryString["user"].ToString();) E9 A. o% g7 C; N+ w
- & ?7 ?) x" x" w, S( P
- try
- H2 n; H, A4 o# w6 q - {2 z6 V; x' a2 U9 N3 v \, U
- #region 用户添加连接池
, O4 n/ @3 \, L; B0 O, N! y - //第一次open时,添加到连接池中
' C& w; t- P$ P' t' X1 m6 [$ V - if (!CONNECT_POOL.ContainsKey(user))& w0 W1 l% B* E
- CONNECT_POOL.Add(user, socket);//不存在,添加& S7 D9 Y! h0 r% v1 W+ `
- else8 i1 m- K. g5 e9 ^0 W8 X4 l v7 w! [
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
. i6 U( d6 I) z5 y" R, S - CONNECT_POOL[user] = socket;
4 }% g( R# N6 x. [) P3 p - #endregion9 J! `' Q8 Z1 y
- 4 E1 n4 X. |. g& |7 T# P
- #region 离线消息处理
2 t6 H0 F* @9 A: g. G& d+ |3 K; y - if (MESSAGE_POOL.ContainsKey(user))
! z! w3 k$ V# I8 r v, {( k3 r - {- {8 L: _, o4 [8 K7 ?% J
- List<MessageInfo> msgs = MESSAGE_POOL[user];
; W" ]4 C+ N/ T6 i* q - foreach (MessageInfo item in msgs)+ h$ R0 e5 y5 o$ l
- {" ~9 w* v+ j+ K( q5 G8 ]7 J
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);, R, {2 r N/ [* x) V+ K
- }
8 C% x+ a( {# |( M" P1 M9 F; _8 g - MESSAGE_POOL.Remove(user);//移除离线消息
5 N! s; J8 u; O4 x! v" k - }
5 n; Z0 Y$ B/ ?% L2 g - #endregion
. {+ s w6 o, U - ) a) j8 }# Q" \' h9 G8 J6 ^9 d
- string descUser = string.Empty;//目的用户
6 Y% O2 Y& ]! r6 b& i( z% E - while (true)2 ?0 v1 a% [) J, U1 Z' e e+ Q
- {' P2 X% U: w3 c$ W* o0 q8 N
- if (socket.State == WebSocketState.Open)- I, n7 C2 J' [5 k( w6 ^) `9 t
- {
* G/ U3 z. p4 f E - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
, c( Z2 @. J, h8 w8 y8 P0 h - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
* s7 u+ p1 r- O' y3 A+ O - 0 o) S# I9 }: E
- #region 消息处理(字符截取、消息转发)$ ^# e0 R' I7 V1 c- q
- try7 y' K* @, C: F/ f! @
- {8 k! b' S& B3 F: e+ V& {5 e
- #region 关闭Socket处理,删除连接池& A8 B2 E4 ]9 g- j
- if (socket.State != WebSocketState.Open)//连接关闭1 _: j$ R1 F+ \' r/ `, H
- { }* }6 X, E. h
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
0 A/ @9 r/ L8 V% O8 j - break;6 A8 v1 W3 [$ A+ Q% e; q
- }
7 M" N w+ T; s5 c! a - #endregion" `: b( Y( X6 U2 a! ?2 t0 B9 j; b# U# s
- ! j" F& [1 {+ [: V, g
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息7 h& r4 w- R/ |# c) A
- string[] msgList = userMsg.Split('|');' r# K# j* v5 T; [9 E: D
- if (msgList.Length == 2)( ?+ Q. d* ?. T$ Z* n
- {5 X- i G, Q* G, ^5 E1 I
- if (msgList[0].Trim().Length > 0)6 i" y+ ]' K, Z! {1 z J$ w2 i8 m) A
- descUser = msgList[0].Trim();//记录消息目的用户4 _. L1 U* y4 j* w+ v
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
+ Z: g! {$ J; {+ F - }
( v% y! F# r; O4 `$ A - else
2 Q8 L; ?( t0 o- ]$ s - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
! n6 D, G- B. b% ]2 Q; p8 } - $ P7 I# G' z# W( Q# R: t
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
: D# O, I2 t, Y6 l - {
v3 e3 F( r, S( ]: \ { - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
' b( t2 Z& Z7 e6 D# [: Y. l8 u - if (destSocket != null && destSocket.State == WebSocketState.Open)
0 X* z4 j4 ]3 N G. n: B - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);- Q n1 }. V% D7 l
- }1 m! W- z7 j/ ~. I
- else6 u9 l$ [- w$ l# ~2 v
- {/ m( U1 O, d' ~8 R; r' x( Y
- Task.Run(() =>4 q8 L# Z1 w1 ~. D5 q; k2 A
- {
# _" d# {. }5 x7 O2 _ - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中7 B4 R7 G ^, P. P7 H' f( l6 l
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
* r+ z( i* v; i/ h) X; L# \; a0 o, N - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
- \4 f2 S1 M6 J$ U$ G - });
) \; D. I4 d6 d. v7 L - }5 `9 I1 d. q5 |8 i2 J
- }
' K- z# p2 A7 _7 D7 z$ ? - catch (Exception exs): s3 |8 S( r: j+ q/ d, ?6 b
- {
( F4 A$ t- j' j5 D' ? - //消息转发异常处理,本次消息忽略 继续监听接下来的消息3 b& _# b) S3 j5 B" A! Z
- }" l! F0 {" k" \1 T" h/ t
- #endregion
7 U) ~% |- E7 J+ G! K" e - }% O3 y# B7 f$ F* W5 ~
- else4 C- ~: N$ U9 l( f; d5 Z
- {
4 k) m! f7 j( n/ Z5 W+ w - break;
9 ~% F" r8 B+ G# X0 k# a8 d* y# A - }
6 u1 u$ _. J& w8 t - }//while end2 J( O% R1 R' t3 h! ^- `
- }8 a+ R+ I! T% Y
- catch (Exception ex)
5 J, [6 Q' w$ V3 O n/ q8 n. r - {5 i) F# N4 L, d2 Y# H( J
- //整体异常处理
% |( D) B. {* ` - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);0 T& Z7 R. L/ I* P7 [
- }+ C5 i1 M" h9 Z
- }
) l) h- }% r K3 {
' f+ l9 M; x1 m; r9 b, R
h! m3 I9 A# F- public bool IsReusable
4 ^/ m3 t( u- n+ a: C# ] - {
5 o( ]$ K( H6 H5 L/ e V& g - get6 S2 e$ z/ z( ?8 l% h
- {
$ r1 k0 p# f8 \" O, [5 b4 z: C - return false;. G( Y/ _2 @2 o- e/ C6 ?
- }
, ]# R. T& G3 R) ]7 F; r+ z% s - }, Y; q5 `+ I6 X- Y3 ^9 {
- }
- d* F; \: G) e1 \- d6 s - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
1 M5 E8 i! K8 j& Z- Y |