服务器端代码编写 1.新建一个ASP.net Web MVC5项目 4 W1 q; R8 K1 m! T' D
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;+ x9 y9 g8 a. ]8 e
- using System.Collections.Generic;1 W- m6 ` l! D1 P0 ^
- using System.Linq;
1 V- {/ m7 U$ d5 q - using System.Net.WebSockets;0 J' x. `$ q" z+ s+ W& |6 f6 T x
- using System.Text;6 a# q: F% w3 f; y) o
- using System.Threading;
7 B# Y. T- r3 e) z6 f5 C/ v2 t - using System.Threading.Tasks;
7 F% b8 S0 F2 D3 _! b - using System.Web;3 U R) c5 J; m/ V. q" u* ^' p
- using System.Web.WebSockets;
7 P/ x. u: V" n8 }$ ~: O. W; z
2 w/ u3 \, a/ A$ j( ~" F/ ~% j/ S- ! X% e3 t, W* \8 {3 h9 f
- namespace WebApplicationWebsocketHandler
7 _8 @0 ^2 S+ k j& a7 R - {
+ k* H t2 f( h) C4 i - /// <summary>
" H/ h+ A6 b: I5 ?4 c: v* z - /// 离线消息- G8 S3 @' y( R( \
- /// </summary>
0 E4 o6 [/ S* E* A9 r - public class MessageInfo" @% a( C1 o+ E1 o5 ^+ y% D
- {0 L9 i. i& |( l) M% A
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)! ^: D5 E( {$ M! p# I
- {( O! F! v; @" y3 n* D2 a- g
- MsgTime = _MsgTime;2 Q& I# f# o9 U# r4 I
- MsgContent = _MsgContent;
7 l0 o+ d. d4 c - }
- w6 u, C# d; `$ W/ f& X - public DateTime MsgTime { get; set; }' m ]& M9 |& M2 d I0 \ i0 z4 P' L
- public ArraySegment<byte> MsgContent { get; set; }8 }- F( D+ }! T# P
- }/ ]) U2 r8 O& U1 N6 {$ K" ~
- 8 s; g) b, m& n
2 T/ k: l$ Q) a2 G- 1 I6 D8 {8 z: s, v
- - q! j- ~) X( E1 R1 @# q
- /// <summary>* }& i7 p% X' `
- /// Handler1 的摘要说明
# Z, ? ^# u) ] - /// </summary>
) q! Q, e: b, ~3 g - public class Handler1 : IHttpHandler A$ k, t9 j0 }/ Y0 K/ V
- {# v2 V2 }/ X/ Z$ w0 N0 T i
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
( u& B( O! J) n1 G. n - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
1 v4 Z& m1 S& }) @. a - public void ProcessRequest(HttpContext context)- r. X( q$ @0 H- a
- {
/ r+ e; Y- k/ w - //context.Response.ContentType = "text/plain";; w( S2 |: Y: g( G+ x* c( X% j& H
- //context.Response.Write("Hello World");
) H! O/ |# k4 a+ [; J* n2 o - if (context.IsWebSocketRequest)
0 |$ V' U$ D! {# H- C; L - {* N+ m4 N' g. c* ?' K
- context.AcceptWebSocketRequest(ProcessChat);- v9 J2 t- p- a3 d7 a7 n
- }
0 i2 ^' s+ p4 }* U - }
6 V1 V" U8 E- l% N) M9 t& b
! m; y) X) n$ m4 y; r& Z- private async Task ProcessChat(AspNetWebSocketContext context)
( C0 N* j' W/ m0 P4 P6 O - {) G9 ?. S* y3 ]
- WebSocket socket = context.WebSocket;4 ^7 F8 l% p$ v: i* {% w
- string user = context.QueryString["user"].ToString();
2 G. A* i( d; I5 E3 e7 `
. x- S/ Z: {6 G4 T- try# t9 R; p F/ ]' l; `; `( l
- {
# |( b/ F! B. ^! }; u - #region 用户添加连接池/ u. @( t( H- h4 ~" `; N
- //第一次open时,添加到连接池中; r3 a" I X' J K, G6 V
- if (!CONNECT_POOL.ContainsKey(user))& X% f5 s# o2 ^
- CONNECT_POOL.Add(user, socket);//不存在,添加
7 _, } V9 C( C - else! t$ x; u7 L: ` ?7 E( w+ Y2 ^3 z
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
, H2 a/ D: G: Z& _6 }$ m$ W - CONNECT_POOL[user] = socket;2 j4 \3 {9 e3 ?
- #endregion( K: Z! t4 i+ j4 f
, X/ ?! [ A/ p+ p4 A# Q. ^- #region 离线消息处理
2 a+ `; s' _( k, d' \: { - if (MESSAGE_POOL.ContainsKey(user)). ~( q3 f+ {$ U
- {
% a$ _' p7 t6 s - List<MessageInfo> msgs = MESSAGE_POOL[user];/ h" c$ x3 u, h3 C6 h
- foreach (MessageInfo item in msgs)! T) ?; ~ Q, p k
- {
2 q6 {2 B- c! U+ k( q8 _ - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
; {* O" I _: X% ~+ Z$ m& E S( M - }
1 l( T+ [8 A% z' @- [7 l7 S - MESSAGE_POOL.Remove(user);//移除离线消息
9 ?$ P' H6 B! v4 T6 L# [ - }
' ]0 W5 F% B4 U) K: s1 z - #endregion. u# b8 @' F% g4 t8 W
- * t: j, \' l: c3 l
- string descUser = string.Empty;//目的用户
+ u* n: g+ V$ m2 k- g& o6 I2 S - while (true)5 v h7 q& c& X
- {9 i% D3 [- ?. Q7 ?* j! W
- if (socket.State == WebSocketState.Open)& w3 a$ F% b8 |5 f; i6 I! L% u& ?+ ^
- {
, J; T$ m- ?* b- k/ l y, [ - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
+ \9 E9 D3 r8 M! x0 z+ _ - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
3 ^5 e3 Q$ _8 k
8 |2 ?; v; o( Q2 K5 b5 n- #region 消息处理(字符截取、消息转发)
) Z+ @* V+ @5 X' i7 l: F8 C - try; o8 r/ ]% M) Q; \% }/ R: l% M
- {1 q9 k9 O) d: l2 V8 D8 c# k
- #region 关闭Socket处理,删除连接池) {' F+ F* D0 x$ L( \
- if (socket.State != WebSocketState.Open)//连接关闭, Q- p- S/ T1 ]; ]( Q! \) |! h4 K
- {
% c& f* v2 F- r' f# Z - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
1 m& s% u2 E3 q7 M; U4 H, S+ @ - break;
$ X7 [7 l3 C) C6 K& b - }
$ \* c5 o ^& s h - #endregion2 P/ \ Q/ K5 d) i% `
_' F1 ?6 b* r7 e. t) x& _- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息, Z ~3 Z" V( B3 C7 B2 j
- string[] msgList = userMsg.Split('|');# y2 ]4 P/ N6 j/ R2 N
- if (msgList.Length == 2)/ a+ f9 x* w1 R- C2 z- I
- {
7 v. h7 Z3 [' L d& @: Z' J - if (msgList[0].Trim().Length > 0)
! Q% k* ~# @2 o8 x& R6 P. B3 O) b - descUser = msgList[0].Trim();//记录消息目的用户
. n" f h6 O$ i5 V1 E0 D - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));6 k7 n) O k1 V3 i* H$ G4 t Y
- }$ }5 }4 k9 m2 d! H! D$ k5 t$ {
- else4 I* v/ K4 F! Z: F8 o+ n$ M
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));7 [3 s& m7 Z) |$ k7 H4 K
- " T/ [$ o0 {4 O/ ^, I: r3 ^
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线0 {& Y! A+ \" x+ l
- {4 V r9 E7 v3 X; v/ x, M/ I
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
- C- o3 ?& t& Y3 k. k" o: Q - if (destSocket != null && destSocket.State == WebSocketState.Open)9 n. c/ I. M! Q9 Z% P9 v
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
& e4 m& p; m6 H/ M - }
+ m" {* `3 `9 E - else
! |# V) U2 x2 E7 a - {
- ^# ?0 Q2 z+ Q. x) R3 ? - Task.Run(() =>' ~6 K' B0 C1 q* G
- {
9 l# d. E! I8 o j - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中# a/ |( v+ B9 \8 z2 T
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
- _# ]* j! \, Q" H$ Y5 ]. U6 ? - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
) _, X8 y! T4 s$ v9 ?' t7 i" ^5 Q) z - });
* B, m+ o+ _; ^& s - }
6 O6 m* t2 ]1 U& _& r. n - }
, ?% N' J1 K% O3 k4 R - catch (Exception exs)) @( I# Y6 m l8 h7 Z
- {
( \) S( m- R$ x5 x2 i - //消息转发异常处理,本次消息忽略 继续监听接下来的消息! j2 K8 G' K& P- q2 W* g% M
- }7 \/ L" s/ l( [4 w7 K0 ]
- #endregion
+ ^ D6 _, ^# \ - }0 ^7 k* j1 u6 H4 `- X0 s. a
- else O5 v' {7 L+ k1 P$ R
- {3 w, |+ V) D2 ~2 X6 ?5 }# k* }
- break;
: t8 S: E& O H1 p! ^) L; y - }3 e9 N }/ S5 N
- }//while end+ c) R, i. C9 o& F4 G
- }
B1 E( Z* r5 j, M7 ? - catch (Exception ex)
" P7 O2 o- E5 O/ s7 {( O - {5 ?: m. e5 n5 C7 j5 }3 M
- //整体异常处理0 {! P+ [9 @& O
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);3 K Q; K5 T7 X
- }
* r8 y$ n1 H0 O6 x - }
% w. h* ~6 V* z4 y/ ]
9 L; d0 I C1 G* v% {- 2 f7 t* _) u9 G
- public bool IsReusable S9 t* f" {7 `& O. Z5 ^3 G o
- {$ P) y$ b4 ?9 _! G
- get, x% ^5 F- _' J, H
- {/ ^0 @3 M9 w6 ]* G- d5 k- C
- return false;
! e; v( u7 D! \5 v a# W2 ` h - }* B: Y6 h H/ H0 J$ l& U
- }8 R" l6 w1 k5 ~% d
- }% ]1 s5 _6 ^; V: L
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 6 ~/ h! J5 H; g1 \6 V
|