|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 / c/ S. C" @) r2 y3 V6 t+ Z0 k
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
/ I% I: c8 c* S) p+ A9 h - using System.Collections.Generic;
% P$ |1 @$ [) f s+ P - using System.Linq;
6 ~% e/ L; W% w/ b+ v1 p( t9 _* e - using System.Net.WebSockets;
G* i' J9 q( a% p+ ]# P! S - using System.Text;
1 d' r3 y) V6 e: N0 j( q - using System.Threading;" V+ n! F5 t! G8 Q" X
- using System.Threading.Tasks;
- L9 B; P) `) l5 Y- \ - using System.Web;. u& F: o' \5 ^
- using System.Web.WebSockets;1 O* R( U- l/ e6 h
- 8 d {7 T! O3 S0 C2 q
- ( ?6 o. R: z+ Z3 J
- namespace WebApplicationWebsocketHandler
( S# R& y$ k- j3 U( ^% F - {
o; H* z; D& y T3 r. H - /// <summary>
0 l* O8 [2 r* C" L - /// 离线消息6 ^$ r2 c P4 N c
- /// </summary>! L! A% ~& _5 W
- public class MessageInfo
8 J. j9 E, s2 A - {- P, v# v+ z( h: q' R( _
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
! ^! a! S$ d0 w% S3 ~# ^ - {: R' j! O( h+ I( G& A
- MsgTime = _MsgTime;, V& j& k- M* V/ U/ Q6 I; l
- MsgContent = _MsgContent; h5 C4 m7 d/ R* P! x8 m
- }
& z7 | l, \5 T - public DateTime MsgTime { get; set; }7 R3 N2 w* O9 {0 q. B
- public ArraySegment<byte> MsgContent { get; set; }
+ ^3 o0 r4 b9 @ - }3 s7 Z1 ^& j9 F& T5 l$ V
! X; t2 b: I& G1 f" X; [0 z" d- / W# x9 t2 i3 Q" g
- ! x/ G H0 [; f( b7 I
! {- k% \$ s* {3 @% y" R4 Z) F- /// <summary>) a* O, H+ ~* {; J& B+ [
- /// Handler1 的摘要说明
) s, @0 C2 ?5 j9 x$ J u1 f - /// </summary>. _9 a5 O i* @4 F
- public class Handler1 : IHttpHandler) ^2 a& Y7 S2 C3 M
- {
2 \ N/ @9 E; z: A D. k- _# K* m6 _ - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池, R9 V# a/ R7 M# `7 j8 y% ]+ G: ~
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
6 ]( U0 e7 o' f& M8 m! w1 s2 F7 B t - public void ProcessRequest(HttpContext context), ]6 x- G0 L1 p
- {
/ h" S0 ~2 z s6 m' _ - //context.Response.ContentType = "text/plain";' V3 b9 F l* P
- //context.Response.Write("Hello World");5 q( C' V- N. L: y3 G* y: [
- if (context.IsWebSocketRequest)
0 g5 m* E# m$ w% S9 k! Q$ P - {0 v- Y- H5 L6 P6 {
- context.AcceptWebSocketRequest(ProcessChat);: b2 f7 |5 s4 R* n0 d" _
- }
* j$ c( C: V% O8 l! A4 t - }
_% J4 [: ^1 A
6 f8 s* o0 m3 ]! ^8 I5 x: n- private async Task ProcessChat(AspNetWebSocketContext context)$ P5 Q. m* p% t+ B! ?+ I8 P
- {! o! [6 M X' \4 y e* y6 ~
- WebSocket socket = context.WebSocket;
* r5 k/ r4 e6 Z; t - string user = context.QueryString["user"].ToString();
* W" V1 R' G. }8 V2 M4 k# O
, ?6 e$ q) E" r f- a4 w& P' `- try; J. @8 O q! j
- {, E* ]' Z0 d% I ~3 e% S
- #region 用户添加连接池
: M# M6 `9 W: y - //第一次open时,添加到连接池中
( ?" v R# i9 p5 Y# n8 f( h" k - if (!CONNECT_POOL.ContainsKey(user))
M8 x8 b( y0 l - CONNECT_POOL.Add(user, socket);//不存在,添加( p) M: y2 F2 s" v
- else
( d) q3 v& b7 l% h }$ k - if (socket != CONNECT_POOL[user])//当前对象不一致,更新! f9 u% e8 ~* C& v: V" K) w
- CONNECT_POOL[user] = socket;# w; _% m. `& ~1 `
- #endregion
! H- @" ?* ?' b
, ~, E) ~. v8 o; j. N- #region 离线消息处理
8 u: f8 j4 [$ H- W - if (MESSAGE_POOL.ContainsKey(user))% S% c/ }/ b5 A) I' K% J9 p" i
- {
/ P+ |& ~- {8 o" x - List<MessageInfo> msgs = MESSAGE_POOL[user];
s' F& D# c( G- \: Y5 t7 Z4 M - foreach (MessageInfo item in msgs)
% ?& j0 J/ o: `! e/ h0 f% a( n - {
$ t0 x z/ f ^& L- j2 j - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
- O8 ~9 n6 S, S4 P, J4 @ - }$ u2 o4 ~! z5 U4 R- ^
- MESSAGE_POOL.Remove(user);//移除离线消息6 @2 r$ c! i4 W; C, F1 D
- }1 s% D- W0 x T( t
- #endregion% T5 h( u" J3 d% ^1 E4 p
- 7 A5 {8 W( n& K' w5 W
- string descUser = string.Empty;//目的用户
% O e- B5 A6 u# T2 b8 f* k; f! E - while (true)
* N; p' M3 h( s2 }. d2 U - {2 R" L1 E' k3 F+ D4 u
- if (socket.State == WebSocketState.Open); @$ H( F. [5 }; b
- {
/ }! U0 C/ J$ b* Q ]+ t - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);5 d3 E$ c) p: q& B
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);8 u) @! W( q- U
- " p8 v$ t5 _7 t7 u k# x
- #region 消息处理(字符截取、消息转发)
7 [$ }$ I) I* p1 c5 ~& V3 A - try9 b" E o; C( \, J# ^9 k4 x( t
- { P9 z8 |- g8 m3 a, d# M- P
- #region 关闭Socket处理,删除连接池
* s) J' Z. t8 `8 P: E6 ]3 ` - if (socket.State != WebSocketState.Open)//连接关闭
4 Z. V- R8 V; d$ P1 Z" a R/ v( e - {9 M7 l2 a: ^6 ?, f
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池8 Y$ M0 P& W4 \7 w! n% r" z% r$ |
- break;! t' M/ h2 a% T/ p6 {- ?) B
- }9 H5 n+ T+ q5 v( o/ N& X: _+ ^
- #endregion
" Z! w* N {; r" [+ D
# X2 l& d! G# \/ k: o; Q9 g* C5 C- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
- q9 M1 Y4 b6 y9 a5 j* v - string[] msgList = userMsg.Split('|');
8 H3 W) v& d; {/ f' y6 D - if (msgList.Length == 2)& ?% u8 P# g' ^$ X Y# Z- u
- {
$ q& j8 l' l$ K: H) X9 N7 D2 { - if (msgList[0].Trim().Length > 0)
" \- j- i, l4 k( \) K- s - descUser = msgList[0].Trim();//记录消息目的用户
: {* r. i* L5 o0 [ - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));0 i. C( s( _3 ^" j% @9 j0 S: |6 |. v
- }
: B( N5 ~5 |& o5 Z - else+ b9 x. K8 E- `1 z. ^
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
% R- K! j6 w9 x# w1 _$ f1 u& x - ( |3 U" c6 ~6 |% J: l% c1 R
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线2 I9 ~ h4 T, }. C! C ?+ O# Z) {
- {5 D2 F- I: L9 `: q) E Y L
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
6 t# h7 ^ h( x$ ]5 w. x - if (destSocket != null && destSocket.State == WebSocketState.Open)
4 D0 }0 w! z+ J7 ` - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
( Z- t+ c9 T; ^( q9 { - }
* y m% y8 g( w' p9 I' n' ^8 S - else
* H) U" M+ b, X - {
0 d) {$ D" V$ y) `5 q% |* n) w - Task.Run(() =>
* y' s" O' g4 F, ] - {
# R2 j/ }' O. P. T' x - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中- e1 q, Q* |" m3 A. E3 }7 b0 |
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
* c& u' F% }9 i" O5 d& y - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息# r6 s# R3 G: r1 W0 j( e' ^% F. f
- });# d6 n, ]+ c, q3 D9 X* X
- }4 c( k/ f* `; u# S" Q8 H& q" ~+ [
- }1 f1 s E. R8 v. V7 Q- M) x, S9 o
- catch (Exception exs)
* _% H* i8 ~2 N - {' {3 j$ f) a( q# Q* j
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息9 v" N+ Z2 ~ g6 @( ?4 z. L
- }9 J/ e# d+ V! z4 F
- #endregion
1 ?" C1 _9 W3 q& y4 a1 D; Q! _ - }
3 L9 R2 ]0 J) q5 C) |8 T2 f - else% i8 F- e" i" T5 Z' c2 z) i+ z$ q4 \5 D3 s
- {
1 D2 _ W/ i! B0 R, \) C4 w* r6 f - break;
" m# o% }7 ~) X* K8 ^ - }
' j) u' @3 }1 d - }//while end" ^( S! J* _/ d3 M% o7 H, U5 l
- }' M8 G* E2 t7 `1 R" P. c
- catch (Exception ex)0 E1 B$ i! F) J3 D% S3 D, ^! o! [
- {
2 w# l& U, _+ P C# R- s - //整体异常处理
7 u; ~6 E: H6 q/ t3 w! u - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
0 v( I/ o" _4 n6 e - }
+ h+ [; b# f6 K8 h7 \ - }* q, m: L6 G6 n+ R
- W- o3 X. z) Z8 d4 b
) w8 A( o& [% M- ^3 N" u( G- public bool IsReusable, v* t. r8 i4 y. N6 W: |
- {
0 @' S5 N# X6 `2 T3 s. y - get. Z5 f8 G0 s. U& y; b" h. @% c5 W
- {
# ^# H* J4 g2 h7 @4 ], v- o+ N - return false;
! P. U% C' F# y; T1 ^ - }& V* s2 Z' ^: ~3 _
- }$ s; `0 F @2 B8 g) T1 a& a
- }' {/ P+ _1 s4 V/ ~3 e
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
! I* ]0 h% S" _8 _4 O |