服务器端代码编写 1.新建一个ASP.net Web MVC5项目 # [: K1 G2 |) W8 L. [7 B6 [5 B
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
) M8 p6 y* D$ z) b2 r7 {2 ` - using System.Collections.Generic;) ^5 Y+ c: S. u+ M, G% u
- using System.Linq;
% F1 o5 ~. ?7 ], W4 m - using System.Net.WebSockets;6 }8 T) O3 s; I1 _3 A
- using System.Text;
- x0 A, @: M! `% m - using System.Threading;
! A# E& x# p5 V3 ~2 } - using System.Threading.Tasks;
& v' v5 w. x2 X# Z$ O. s - using System.Web;
0 o4 f, ^2 C9 O/ ]9 O% k7 ~ - using System.Web.WebSockets;
$ d9 f3 P' b$ M1 @$ f' f* A, W( d - ! a% L, s! L/ y8 r
- " i) C5 Y! I I7 R& F
- namespace WebApplicationWebsocketHandler
8 z% n& B! Z- g6 L x6 v3 K - {
[0 o: R; ~: {7 d1 j7 ` - /// <summary>
: B: P# e1 R G3 M% W( U, U. d( x - /// 离线消息% x1 C" i0 ?& S# Z* m
- /// </summary>
h$ U( i- [* J* L8 B# e! i' T% U - public class MessageInfo6 T2 X' X9 o& O7 w* O/ C7 r
- {0 L1 O- e! v1 x B- B
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
* r! r) v3 l6 W( Q' ^ - {
/ I( b. z T) K1 y1 L - MsgTime = _MsgTime;0 V4 H8 O5 z% z( y
- MsgContent = _MsgContent;
' z1 f; n' I! @) ^" y - }
0 Z& w4 j* m, X- v) Q, b - public DateTime MsgTime { get; set; }0 x/ E3 `7 C3 u: ?7 F2 I. z
- public ArraySegment<byte> MsgContent { get; set; }
6 V% {2 \ O% ?2 j1 a - }' G8 q5 x2 E/ p' y
- 5 B3 X6 u) ]: \4 R
- 5 c- g+ O1 _( E, t+ A9 G2 H% C
% y' B- h! s+ z3 Y
. ?" f: |6 E# u% [& z; w2 `( R- /// <summary>
1 L' P3 I, t: D2 e/ Y$ ^ - /// Handler1 的摘要说明
' E: O3 H' H/ N3 f( o- h - /// </summary>
) t8 ^0 N. F* @0 M - public class Handler1 : IHttpHandler
1 q& V* v% V3 a3 P5 y1 k$ ^$ i) R - {
1 ?- q, ^5 ]% S - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池6 l/ Z. ]* ]* w: ^
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
( o) J, n2 G0 L* n* t: Q6 G - public void ProcessRequest(HttpContext context)4 G7 F( J8 }! v+ t! x# A
- {
' F& c; ]3 S% l$ ? - //context.Response.ContentType = "text/plain";# L! y+ w! B0 d
- //context.Response.Write("Hello World");' y3 w+ \ Y. X
- if (context.IsWebSocketRequest)' U& u5 c% B9 b/ P- C
- {, ]6 j) P# q+ ~. D0 _
- context.AcceptWebSocketRequest(ProcessChat);6 z- }) b" t; k- T+ ~ C% k
- } ' Q( M' k5 L5 V' E3 d2 i
- }# P4 |; O, E$ J4 S# ~
+ `- ~1 a( W6 P6 w$ G- private async Task ProcessChat(AspNetWebSocketContext context)
1 U: g5 c M _; ?2 ]+ `8 w/ y - {4 `: b, l' E z
- WebSocket socket = context.WebSocket;
( ?! y6 Q- d6 ^! t. k+ E: k( ^; ~+ S - string user = context.QueryString["user"].ToString();1 z- t) j9 g3 ?3 j
" R* h4 _2 l y9 Z: Q2 ?8 p- try2 m! j" X) a( _7 Z5 B
- { A- L, g( E. Y& Q4 I [# F
- #region 用户添加连接池! y' \1 Q! x" M
- //第一次open时,添加到连接池中. S1 z% S! H3 z5 l* R( d
- if (!CONNECT_POOL.ContainsKey(user))
4 n+ h6 Q; W0 w, N* e+ I* ?* o - CONNECT_POOL.Add(user, socket);//不存在,添加$ L9 E: v0 V" O4 \- j5 d
- else
+ S* L T2 h1 g( o; _ - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
7 g2 j2 I# ?5 W( u8 F1 X x - CONNECT_POOL[user] = socket;
z0 K& y G0 p - #endregion$ y1 j. x( e: P; h1 }+ D$ `
- 2 f6 _: E6 X6 A0 o/ _
- #region 离线消息处理
% a! v. R6 }" u: O - if (MESSAGE_POOL.ContainsKey(user))* M: G. Y$ N3 O {4 P' t$ |: {& K
- {
- S# Q4 Q' n, } L - List<MessageInfo> msgs = MESSAGE_POOL[user];
& F7 s' p. y' R- S9 M+ G - foreach (MessageInfo item in msgs)) j: n( ]7 M" a9 s
- {: g5 q6 `" p: }7 e. i. x% y
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);2 ]$ Q; L& x6 y7 F& f( O! O, A
- }% p6 G V4 w( M$ d w& @8 G
- MESSAGE_POOL.Remove(user);//移除离线消息
/ j0 A" L: |( Q& N% x7 U - }- K4 E% a: P7 L1 C# F
- #endregion/ l0 i' C+ d i4 m! ]! L4 j2 i
5 G! J" o) b& J$ [( A- string descUser = string.Empty;//目的用户! b, G" V( V& I$ q3 Y* B
- while (true)
7 n. E: l' B# {0 B1 v% ^ - {
1 g1 p2 x& I- u. i3 I* ` - if (socket.State == WebSocketState.Open)" `) [4 V* \2 q7 C {. w
- {/ ^$ f, B$ a. C: L
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);% f4 V4 B1 S$ [- u
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
% d$ U0 T9 t' O; h - ! U' B) j& G1 f3 C" o! K
- #region 消息处理(字符截取、消息转发)
k2 s. m- Z) s O; b - try
) ]1 f1 n+ ~! {4 u1 O4 i - {
! [9 l i% x1 E - #region 关闭Socket处理,删除连接池
) ?) F" ~: K, S. g5 T0 a I7 i - if (socket.State != WebSocketState.Open)//连接关闭
( ^# s. A# n& P7 [) e" u - {0 e6 q0 Y& o8 Y9 Z+ j$ C/ d
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池: I3 I& X$ h: Y2 M" r
- break;
5 [6 P4 j* x, N' n+ m0 e4 F - }5 C6 D& W! F& l* B
- #endregion+ e. t# L/ b3 y: c, e5 x8 f
- ) ]% |8 A5 f+ u2 b6 J/ }
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息+ E! [7 N' S" h: X- J
- string[] msgList = userMsg.Split('|');
& ]6 g5 M' T1 ~& n! j9 L - if (msgList.Length == 2)! G1 W) r5 A; V1 [9 q! Q3 Y9 D, q& w
- {* Y8 h3 N2 `1 S
- if (msgList[0].Trim().Length > 0)
6 c8 l/ Y, {5 r - descUser = msgList[0].Trim();//记录消息目的用户3 k( T2 P$ w P+ e- x; z
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
: Q3 L; F! p2 C - }" H# Z8 {+ K2 a9 w3 l4 X4 [
- else
/ z+ C: p! f+ h1 k - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));/ ~2 {$ y0 Q$ W% [" {
- - }- G6 M: U( M: G& O8 _9 e- M. T2 `
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线% p" L, y& N6 I& T( a8 ]# l2 o
- {
; A3 C1 E5 ^8 x, B: |+ t - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端; g$ a/ @4 n9 y2 G
- if (destSocket != null && destSocket.State == WebSocketState.Open), M8 Q @5 b7 n7 @. m! j( p5 e
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);5 w. k! o! Z1 w( C- v. I. X5 V) j* k
- }
6 O% z8 _* ]/ _& T( l - else( @1 E. O$ z4 b1 y& B$ }" o) g
- {, I$ J2 v P6 E5 {$ j6 |5 }* f! Z
- Task.Run(() =>( n) h5 a$ p( ]0 l
- {
* N% x+ Q1 Y3 E# k( y - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
$ h7 R" T7 @6 R. C# y - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
5 Z9 u& q$ }9 U; l - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息4 O* E+ J5 I! M* e2 _ T5 c
- });
, z6 K4 x0 p. _ - }
$ [& z; s! j4 Y% f& G - }# w1 w7 I9 c4 ?2 e
- catch (Exception exs) i4 m' g2 i9 j9 m, Z
- {) t* g* x5 A, x) y# B2 q. H: ~
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息2 A& }, _2 x- T- E3 e( p" A
- }" _8 U6 l/ y5 K% K* L
- #endregion5 M$ `' F6 A$ V% w6 T* v
- }
2 l& ]- _ w0 A6 K - else
' y+ n. e/ o2 {/ `6 W6 p* T - {& Y# m# I1 ~( a
- break;
) h5 O. j7 g0 g# ?' w* V - }
1 ]! Z0 J n( [3 `' p! m; V - }//while end Q- J7 u) K2 K
- }
/ ~' {$ u( j' X - catch (Exception ex) i7 S }0 x2 y% \# l
- {
! p" [+ g, q5 L - //整体异常处理2 M+ O1 }. {' f) N E
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
& O, U9 q; Z* N. M; _! W8 ` - }, U% b9 _* i% ?& I$ ^, j8 |
- }
2 h1 @/ M- S; O3 D( i# O# o - ) d5 V: Z7 A5 Y% ^- ?
7 K- K4 F$ u# Y0 Y9 [( T, \' A0 x- public bool IsReusable
, T' `3 b2 H) s2 Y/ D; o - {# A- R z6 q& O2 j. z. |# |
- get- X* r4 s5 m1 l) V3 l K
- {
1 m/ Y, @& X0 ^$ H - return false;3 ~0 t8 V' |* k* i2 G
- }
& {3 j8 r1 { j- { - }
" J' F# ]+ r1 y, X4 X/ X - }4 `6 [) q9 t, j7 O% u
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
4 B5 b) K. N6 m, p, ?: \6 } |