|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
1 I0 m+ ?3 e; u$ E+ g# R2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
; k) e8 B. X2 X+ E. B - using System.Collections.Generic;
- ^) p$ k% V0 G( \( R. h8 t* _ - using System.Linq;
6 E, K6 E9 N$ v9 a E7 Z0 R - using System.Net.WebSockets;
- o8 h$ w* Y8 [+ D. H - using System.Text;
# d* V1 d Q1 b% M, L, n - using System.Threading;
9 X4 I& N2 C% x4 ]6 `1 P7 V - using System.Threading.Tasks;2 h. ~$ M! R- J2 U* H' t
- using System.Web; S5 p9 y3 q" a+ \& I% X
- using System.Web.WebSockets;- E, G o" p1 w
6 P3 P/ t9 G0 W; G1 L; L4 y: [- ( l7 Q& ?* ]3 Z+ b
- namespace WebApplicationWebsocketHandler
5 o W% ]6 N3 |& w: j7 k2 y - {
. m& }0 s1 f1 u: N- X+ i - /// <summary>
$ {, I; L" s5 A; j D( d$ y2 w6 _ - /// 离线消息
|7 |9 Z5 P5 Q - /// </summary>9 \7 Z7 D4 Q i/ H
- public class MessageInfo
: E- y6 Y7 {9 O0 Z$ D4 D% d e0 E - {7 c, X, S& Y+ b
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
+ x& U( f3 r' @$ n - {1 S" v3 E1 j. f8 K* n) ]) s+ W( w$ M
- MsgTime = _MsgTime;/ f* E& E0 x( x' K2 X) P
- MsgContent = _MsgContent;) G* }; e3 `3 z8 d6 F4 c( Y
- }
# x0 l) `8 D% P3 S0 W2 T - public DateTime MsgTime { get; set; }
1 I+ L! [! u. w% o: r - public ArraySegment<byte> MsgContent { get; set; }/ R/ d @6 _' p* F% k
- } V9 e b+ z b8 E7 G9 d) d- |
1 n2 r9 N# y s0 V8 {" ?! P- , T+ R) \) Q& ]* ]
8 \) q( e% f# x: t( ], z5 o9 q
" v5 M+ ?4 V9 {8 V7 }- /// <summary>6 ^5 ]6 B! N& W$ E
- /// Handler1 的摘要说明. z4 B: h3 s2 ~7 E& q
- /// </summary>6 d/ o$ m; v3 p! `9 n' c. M8 f" \
- public class Handler1 : IHttpHandler1 o' R/ _+ ~) j5 x) Q$ L# U& M
- {
$ ^! n% v3 g; o7 O# c( b - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池3 B5 n! b9 k3 e! S5 N
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池" g3 M; p4 {$ R9 J
- public void ProcessRequest(HttpContext context)* a$ ]0 T' I' a4 K
- {
3 N8 u: [+ I9 H, D4 C - //context.Response.ContentType = "text/plain";
1 ^4 h8 a% I8 \7 |! x - //context.Response.Write("Hello World");
- v* @. Y! b4 E: K% Q9 V& m - if (context.IsWebSocketRequest)
1 r: v* r) O/ ?- s - {
$ Y8 c8 r9 n8 @0 | - context.AcceptWebSocketRequest(ProcessChat);% @2 ^8 f0 {# i# k
- }
6 E4 P; G: J+ y9 Y$ y) X - }
7 ?$ n& M' n& _* U" x# k0 J+ @ - 2 B0 e ^, \& T) g) ?5 Y4 Y9 ~- H
- private async Task ProcessChat(AspNetWebSocketContext context) d" a& j2 y c7 d9 t
- {
+ }) `) | a3 Z - WebSocket socket = context.WebSocket;
. m# l) p6 ]8 V8 g9 C E+ o% h& I - string user = context.QueryString["user"].ToString();( O/ X1 N9 K3 u" @* B- }6 G. [
- - T d0 t6 o/ K; j2 V- [
- try) J" i! o: w; f$ `3 ^: v
- {0 p0 N( X; C- s, p" g! V
- #region 用户添加连接池
k- C2 K. t1 p! Y9 T1 I - //第一次open时,添加到连接池中
9 |: L, R" ?9 b2 {" k - if (!CONNECT_POOL.ContainsKey(user))! n, B# e8 V/ g h( o% U
- CONNECT_POOL.Add(user, socket);//不存在,添加9 @# }8 V6 \7 z
- else# J: q& l. q* B
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
" z1 M/ J; y- r y: v4 Q4 h9 B( [ - CONNECT_POOL[user] = socket;1 u. }2 D* O, |2 a& K5 p
- #endregion, _/ ^. s- s4 J% K, C# n
- . n- e% `/ M' D
- #region 离线消息处理$ k- Y/ S7 |" B+ A0 S) z8 X
- if (MESSAGE_POOL.ContainsKey(user))
0 B9 S6 b, h* q7 a. m G - {
! j$ S, B6 w& g4 A - List<MessageInfo> msgs = MESSAGE_POOL[user];
( a4 e8 A: s7 } - foreach (MessageInfo item in msgs), H- q1 W" T7 K* w1 N
- { H. T- g8 ~/ `: V6 y% t6 B$ i
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);% q# e$ f0 j8 J1 X; m
- } O, h" Q* j7 V; n/ D6 M
- MESSAGE_POOL.Remove(user);//移除离线消息% \; B; W5 G3 G/ e0 T
- }4 d% @/ \( ]7 f$ G- r4 `
- #endregion; H2 `; Z) F! {6 w* ?
- - u$ k7 S' w Y) R
- string descUser = string.Empty;//目的用户6 h- b0 I/ d9 G& \( `* L- x' Z% _
- while (true)
1 c; ~' u" P# Q, ^ D! ] - { I6 F' R* b8 J- m L
- if (socket.State == WebSocketState.Open)
2 }3 j3 R4 g5 `/ _- E - {, @$ K* A' E6 k& m+ D$ a! |
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);8 V" k$ \ D3 U& S2 d' u
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
/ q0 m. `* s( c
% Y2 I9 Y7 a- ~! R- #region 消息处理(字符截取、消息转发)
" Z5 R2 z( `# [1 M" X6 W - try
4 `( X3 l3 E5 L - {
5 E$ Z# A' Q" n8 W$ h5 i - #region 关闭Socket处理,删除连接池
$ E$ d* L: ~4 s7 i - if (socket.State != WebSocketState.Open)//连接关闭
' q0 ~5 _7 {9 n2 x9 f& p - {
2 L& e! G9 @- e" L5 Q/ B( a - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
8 u7 ^0 O" Z4 r- J8 O - break;
& y% ?5 s1 a( s& T" J- Z+ q: F - }2 V- C s% v. R& i6 ~+ T% D
- #endregion
. `3 l+ d5 ]& Y! {5 G u4 s
" ]1 Q9 u% y& Q- E- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
0 g, Y9 t) X H1 J - string[] msgList = userMsg.Split('|');( b0 S! G& u! A: W! P0 m! _) k
- if (msgList.Length == 2)) ~1 f7 S. X" ] J! N! z
- {
( k! E/ ], \/ H P - if (msgList[0].Trim().Length > 0)
7 h) M6 j1 U) K1 n* D% A; d - descUser = msgList[0].Trim();//记录消息目的用户
) w& Q8 w' P8 S; e8 ~* J - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));5 Y( Q$ r1 d4 ?3 g
- }- n- l; }* X. q- m& b
- else3 X. y/ [, u& L& d# v/ u, A+ J$ A
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
5 f5 Y! U7 U9 r2 Q- m* B - 0 Z# i: a7 p; b- G: |% {; U
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
. K9 @$ d/ { i - {
# ] w C2 B2 V - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
3 g. H( Q- A5 Q' U5 o - if (destSocket != null && destSocket.State == WebSocketState.Open)1 x- N8 s0 J9 {1 S/ X
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);2 J- C K, {5 T# I9 ?# {' ~ c+ c
- }
" O" w! k2 V1 O3 U# L - else
h' I4 K8 S: @4 N3 W- u) c* t - {
) K' C; c+ z% Q - Task.Run(() =>
" {) Q! b% e* d' h4 U* U9 x( t - {4 B0 p- e s/ e3 n7 |7 N& z5 v
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
% _+ s8 ?& n3 L& c3 e - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
; |. F+ w7 a; c/ {0 r- ?" c' T - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
- V) I5 s b$ w2 m5 H - });
) [ E! r, u- P! z) m - }
" g, d; p8 |4 \8 f8 Y - }/ n7 V @/ `9 [5 J0 I2 k
- catch (Exception exs)
& p) k4 N5 W! Q# @ r - {
2 S+ g" d7 x9 M; N3 L - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
q5 H+ q) x- N0 `, d) U - }" c# ~& R, M+ Z# a, ?
- #endregion
5 x* \5 m) k! w1 H& K7 N - }, k: `- H: A# `$ b ? C
- else
/ r4 _5 @6 S }, K0 s- [- J - {6 o" {3 E6 K- l" }; w
- break;) ^' V! Q' _1 O9 d, I% p$ W9 @
- }
) e2 w. t) P7 F( A - }//while end" I& {) P* m; U$ e* v& r/ V
- }
/ f" U0 S) {% E - catch (Exception ex)& L7 i6 C* k' s% K$ M
- {( g: e6 Q/ i# }- A8 P, q6 |
- //整体异常处理
$ U# l. \) V6 h" W, d0 R8 D" ` - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
3 X) @. t4 w3 a) z: P! ^ - }1 _' c: {- x/ E: g
- } s' z, |2 N$ N8 A$ u# [! j
$ t) v; v- b( O4 g, G ~* H, e7 j
" n4 C5 V2 t( C$ J) r& v- public bool IsReusable1 O: j, b! w6 G2 s) P
- {, l5 M8 q' g) C- t! j6 p- F
- get& V i0 e) w3 |1 Y3 _
- {5 D {0 u( y4 W2 d/ X
- return false;
# }. W' E- _/ q- [! f& @ - }
f- P A, N# }4 S( C$ ^2 Y - }
5 | o; m* `8 I5 ? - }
, e& E9 F& Z- } - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 2 n/ l* N! E6 `- Q
|