|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
. R' g$ T1 ^, u7 u) W5 \2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;/ E' m& w' g4 V% ]5 Q4 N$ _# Q
- using System.Collections.Generic;
4 K' f. U% m# L+ i) j% l - using System.Linq;
9 h2 ^' l; n& C N+ m1 T7 H- V - using System.Net.WebSockets;
+ d- t+ Z" i4 ~3 r% b - using System.Text;
) U$ I' ^( Z3 Q# W4 q9 ^ - using System.Threading; R0 {* y2 [9 ]
- using System.Threading.Tasks;
1 m: x/ Q9 ^+ V& @+ t; @* y$ E - using System.Web;
6 x t# I k y! v, A! V5 g - using System.Web.WebSockets;5 F6 E1 o7 I( Y' i
- / m% B2 D0 O! W
" G+ P5 l/ Y1 R0 A- namespace WebApplicationWebsocketHandler
. x) N4 T# j1 M% r @3 S& x - {
/ S# {2 D) Q( V, [& }6 A7 U" x - /// <summary>
3 A1 b+ i- b$ o) P - /// 离线消息( Z A6 h# r' g) v# k
- /// </summary>! O5 ]9 t: {! P+ Y( f
- public class MessageInfo
3 J) U& N, L# I, f- y! n - {# ?9 r' }! R3 ~: D0 y0 i2 j: B( _
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)3 _ z' s" @+ k3 v% t1 l
- {
4 W+ n/ i: C ~/ ?2 S. d. Y - MsgTime = _MsgTime;( a: H+ S1 H: H/ i! Q
- MsgContent = _MsgContent;
$ I; U2 l$ o2 y2 F: n - }. O9 O# o' Y( {; ?4 Q
- public DateTime MsgTime { get; set; }
5 ]+ q* @; p" l1 o8 Q4 ] - public ArraySegment<byte> MsgContent { get; set; }' T8 f( I7 ~- B" y8 ]
- }
# W# V3 L8 j! N" w4 @ w. L
; @: a# A8 |7 W2 _* D' _+ k: ]! Q- " B) R* m4 q/ U
- $ Z2 j: Q4 b- s& ]! n$ g. L) B; v
- 4 p0 X) F# ]9 q. {
- /// <summary>
: Z" J- Z Y; _+ r9 Z) h - /// Handler1 的摘要说明6 u( }: A4 ^( S3 p% ]0 X6 \
- /// </summary>
# l5 _2 _2 N5 \, G - public class Handler1 : IHttpHandler
0 s' J/ @: J* y8 u - {# J' ], B$ V( v& \6 K4 h2 L0 D
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
, F" z( Q) v# J1 E% C1 i - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池4 H/ w5 G( u5 H1 Y! X
- public void ProcessRequest(HttpContext context)# ~) { {' ~4 I+ A1 V! ]
- {
! y$ x7 p9 T2 X: q+ Z - //context.Response.ContentType = "text/plain";' e! S! d9 t; G% D. I
- //context.Response.Write("Hello World");
5 X0 @ Q1 k( _# _ - if (context.IsWebSocketRequest)
1 F/ U8 p+ L0 V; ]+ H. y, n3 A, e - {# Z D3 P/ o B- n6 Z% {
- context.AcceptWebSocketRequest(ProcessChat);
1 v8 P# w9 T' x8 y1 w2 ~$ ] - }
6 q t3 B$ R/ X0 R - }
* C! M! M% T4 ~8 A3 v! D$ d
5 X' u1 {. n, \9 C" g% X# s- private async Task ProcessChat(AspNetWebSocketContext context)
% N) w( }: T( u1 ]+ v! f1 i$ \9 f - {
0 E( U; j7 A$ H* N0 _( G4 Z' ` - WebSocket socket = context.WebSocket;
9 e5 U1 @% W' Z: L0 z# y - string user = context.QueryString["user"].ToString();, n7 \+ J7 w( W
- ' H$ o3 e: V7 d7 l) t. U
- try! T1 R0 m0 K1 V+ V: |
- {* S4 N0 i4 b* l6 u
- #region 用户添加连接池: _+ u" y4 Z6 b s1 ? y
- //第一次open时,添加到连接池中
/ t6 N5 A9 e1 S: ~. s - if (!CONNECT_POOL.ContainsKey(user)); B% E- D% j% {8 K5 e+ s
- CONNECT_POOL.Add(user, socket);//不存在,添加0 Z d4 \: j D2 M& }4 N5 a3 I
- else$ K5 V a, { w1 o, L
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新) d5 C0 t& _. y
- CONNECT_POOL[user] = socket;9 F, b* ?* V! ]5 S1 V. G3 @
- #endregion" n- M- y6 n" S- L% G. G) q9 X
' G1 O& ]! J/ P- #region 离线消息处理
8 o9 l9 J- f. W" e - if (MESSAGE_POOL.ContainsKey(user))
& p! {/ O, d5 N! U - {2 z/ F7 e+ r/ E; y
- List<MessageInfo> msgs = MESSAGE_POOL[user];. s, X. s! A2 `% E+ t9 E
- foreach (MessageInfo item in msgs); g+ v' l* }' ]( L4 T% ]0 C3 \ d
- {
' ?; v% U8 L, ]+ X' [* { - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
; p. ?: _- Q6 f; v9 T$ g( X& g( D& u - }
6 {8 t+ L9 |% C: x - MESSAGE_POOL.Remove(user);//移除离线消息* {! K7 J* P- r% X0 j7 U
- }* w( [' V& ^0 x. ^" R
- #endregion+ @& a1 A4 ~! `; f! e
4 x0 h: I8 g" Q- T: i- string descUser = string.Empty;//目的用户4 k, Q/ W! K& F
- while (true)
" P O- e4 P( ]5 g$ m - { g0 s2 n t9 d5 Y$ ]6 L# K
- if (socket.State == WebSocketState.Open)
# p# O, s. ^; f$ W4 } - {1 b5 M4 ]/ o" X6 w" }
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);) m, E& n6 r: O& U$ x8 P
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);4 v) j% v/ e) q$ r+ n, C9 v
- # x: k2 m3 A5 d6 r
- #region 消息处理(字符截取、消息转发)4 {% x* ?) ?5 k8 ]9 Z( R
- try
% t. c X: |; L& L* t - {- ]0 Z8 Q5 O3 G7 ]1 n6 Z1 k
- #region 关闭Socket处理,删除连接池
, `1 A- k1 G- ^% [ - if (socket.State != WebSocketState.Open)//连接关闭
% Q: \- T8 e6 u( o1 Q# \8 E1 z - {; L5 H% W0 [& O j0 B) c P
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池" u9 B$ f" n" C6 W0 ^
- break;. }1 I. o. f; N0 k6 |* A* m
- }2 g, `5 n" v; |+ s1 }, D
- #endregion
1 K: Q7 x- o/ v& w% C7 V6 L2 b
1 P/ b, n5 `( W" e- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
2 ~2 f! _+ Z7 D* \ - string[] msgList = userMsg.Split('|');
3 P9 D& J$ U2 y# E: ~8 w; b/ B - if (msgList.Length == 2)
1 R0 d8 W1 ]/ V - {+ j0 j+ T1 k! g4 B8 [
- if (msgList[0].Trim().Length > 0)
, P1 U8 @+ O! l) O% m! b5 w8 }( z# }3 } - descUser = msgList[0].Trim();//记录消息目的用户
8 @% N" ~' {9 e- f! }3 @: M - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
4 Y) ~ Q1 ?* X7 [7 ~ - }- V3 N f0 s* m% j$ O2 D' W
- else- \" z" l: K; x$ C3 n. T
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));$ ~- t3 U- g% Y5 J0 a
- 1 M3 f; m7 r9 v. ]. U' ]" f
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线" I. |5 T2 @' a4 D0 k! p
- {
. n) x0 T, I$ B3 { - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端1 g0 a/ h: Q1 N2 [: c* q. s, L2 p
- if (destSocket != null && destSocket.State == WebSocketState.Open)& g/ Y; F; B2 K- S
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
2 q, d1 {. L1 K8 S2 f/ E - }8 r2 h( f) }2 ~
- else; L9 `/ p& T/ C3 j `# {
- {
/ i5 Z7 E/ D+ N( o - Task.Run(() =>& A9 b, h' a. u
- {- a9 h1 f+ z r
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中4 h4 W- d# f) H- q0 [) ]1 Z
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());4 z2 [3 q V/ T, M( u3 ~3 ?
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
8 B6 q& x+ L6 c - });
, p' k; B/ O3 j; i - }1 m/ O% q! v+ Y: Q* D
- }7 k$ X% C, `- r& z Q7 q% s
- catch (Exception exs)
7 l+ F- |2 z# ]$ \+ t/ K- e& m - {
+ R) V! ]# u6 \. e1 p1 t# d% C9 c' d - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
. k- p8 d' e, c( n - }
. O( N7 k+ \9 S# f- K - #endregion, I$ e1 N5 y' U2 {. I) R5 t: s
- }9 z& I9 q" g% p% h( O
- else2 P( C+ `: G6 }7 v- I
- {- _; w T& K3 h' R0 \4 S
- break;8 c9 \) F/ ]/ _5 o0 G
- }# o/ o! X, a! R, G& y
- }//while end
& r. t; G( o n" Y - }
5 V( ]. _- c- c2 V' h4 k - catch (Exception ex)
$ p, f( l% \/ S - {# r' l8 P% q# t: w' d1 l& c
- //整体异常处理8 Y' t( \6 i. q7 N/ x, v
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
z! ^! x- k! F n - }8 S+ c+ T' {7 |- w8 T# e
- }
: M& i6 J8 g( ]# _9 H - ) S0 m7 @$ e0 q/ A
- D4 f# W, y0 |
- public bool IsReusable
* H x: ~* ^ ~ - {
! \/ d$ ?( B- D1 w - get* X0 ]5 H) c* q* U$ |; e }
- {* @! `9 H: C8 j" E0 I4 x4 J! q% A
- return false;$ V. g- U7 L l$ x
- }
" Q$ m) W3 q3 l* o$ }# b7 X: H2 w - }4 M& E/ k3 {! k+ w# R/ l$ N
- }. v& {( X$ f' s% m& g
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
) ]% X( M$ n' B0 V- E( n6 c |