服务器端代码编写 1.新建一个ASP.net Web MVC5项目 4 Y) P I4 w' ?
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;( _" _9 f! o3 N* q
- using System.Collections.Generic;
Z+ n8 R8 j4 ?" O3 O+ O3 Q - using System.Linq;( d+ ]! ]- v. |+ R6 H' g
- using System.Net.WebSockets;
& n4 {- W8 H% L! H% ~ - using System.Text;! y! W" u6 b# X+ x, w
- using System.Threading;
3 i5 n6 h7 }6 Y1 N - using System.Threading.Tasks;
6 I% K0 U- [+ n" ~ - using System.Web;# E! V" d4 T- z7 `$ w
- using System.Web.WebSockets;5 \( U S8 E0 ?1 r. P% D% }6 z
- " [- q% Y/ w3 l( O: X
/ m) n" k& K! d& ~" T- namespace WebApplicationWebsocketHandler6 Z8 R; P% }$ }( v4 | a
- {3 r9 O" T( G# ~
- /// <summary>9 a5 }+ @) W1 `$ z. R8 I
- /// 离线消息
* F/ ?6 l4 q% N6 h1 Z - /// </summary>+ K T4 f& B- C3 g* w
- public class MessageInfo/ Z! u% `$ [8 }+ o# H \' [8 L
- {# w; R8 S& ^, Z/ K% o
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)1 l+ y5 p0 H+ `3 `9 ], V7 ]
- {
6 g, n' b% N3 p, |& K+ s6 s! M7 M- l - MsgTime = _MsgTime;
2 [( I3 w |8 c0 h - MsgContent = _MsgContent;, e* ^' M+ k% }$ W1 }
- }# R, X2 d1 c) K& ?: B0 r1 \
- public DateTime MsgTime { get; set; }
2 p e @6 q, V9 K1 P) ~) J8 r - public ArraySegment<byte> MsgContent { get; set; }7 I2 ?) r: ?/ C' R3 L4 U8 U9 i
- }
5 z! |. Y& z& q5 a; ?+ v, r
' X o0 I3 v# i$ G0 V# D- d {- # T* E7 J: |1 Q$ i) W
- 4 Z7 ^6 j1 X$ w8 i) ^. @3 @, \
- : c$ l, b: L/ _$ n' j
- /// <summary>
2 F' k9 n: c* _. U - /// Handler1 的摘要说明5 v3 {; P5 s8 W: A1 |
- /// </summary>
* l; q3 a0 F* ]- p, m - public class Handler1 : IHttpHandler4 ~9 P5 Y. t/ V5 y
- {
+ s# A- M* A5 y" @" T! e - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
% h1 e( h# d% t W: I - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
6 P2 L- @( q# H. K7 N, R - public void ProcessRequest(HttpContext context)9 [7 q( O9 g5 D% a
- {
; C' u/ N) B* N$ G$ ^ - //context.Response.ContentType = "text/plain";! w/ U1 G/ B: c. |! ^) Y
- //context.Response.Write("Hello World");
7 M2 I1 s* u7 F' H G0 i% } - if (context.IsWebSocketRequest)
+ x! D! d/ q; d7 Q& g - {% Y7 P2 b# [ o- \9 L3 X
- context.AcceptWebSocketRequest(ProcessChat);1 t" |" |% }3 G# C" g |. Q2 y! R
- } 5 Y `) h# T4 m( p# u6 v. |; e
- }
% C2 i' U- v V4 ~: Z' U
/ D% O7 g1 ]4 S; d3 F' z3 h+ N$ v0 [- private async Task ProcessChat(AspNetWebSocketContext context)
1 K, ~: ]# r7 {3 |3 I - {
4 r9 z, ]" t/ R; F - WebSocket socket = context.WebSocket;9 v1 s! W5 s# s9 r! d( r0 J
- string user = context.QueryString["user"].ToString();0 `' X) |+ b4 Z8 H
* J5 k; p- O% `3 J0 p% t; V* ]- try
; j" A8 L) r+ H' r' [ - {
) T7 ^' f. X3 \6 U - #region 用户添加连接池, ?4 ^" ?5 r; A/ \: w2 N
- //第一次open时,添加到连接池中
3 k! L& U, Q. [' m4 t/ ] - if (!CONNECT_POOL.ContainsKey(user))
& y2 V" n- h6 h. m - CONNECT_POOL.Add(user, socket);//不存在,添加
9 ]; l* u+ ]9 ~8 D/ F$ _( f - else
- c i# n' b5 M Z7 ^/ b/ V) A - if (socket != CONNECT_POOL[user])//当前对象不一致,更新9 v. e2 }' `. N0 p; t
- CONNECT_POOL[user] = socket;
) `. m: U. T" U - #endregion
& y( j+ z0 e) B5 t5 ?8 [1 N( {4 L
8 A/ b0 ?' z% [$ Q2 N' A* K* L- #region 离线消息处理
: [% K* N( ~; p# R5 h - if (MESSAGE_POOL.ContainsKey(user)): d" ^/ s7 w r8 L( l9 Z* {
- {
5 n* z; V( ^) z7 p- B) d - List<MessageInfo> msgs = MESSAGE_POOL[user];
; k7 Y( p! f* \" M" J" d4 | - foreach (MessageInfo item in msgs): k' N) K- V; L6 H v, Y9 A) Q
- {
: N4 f1 R+ |' n - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
; T) K7 F# o; }2 Z - }
8 k5 M, \0 ]: J8 Z& K# c! k) [ - MESSAGE_POOL.Remove(user);//移除离线消息: `4 B- Y# t3 [
- }/ w+ T7 A6 ~: w2 Y: M; Q
- #endregion
0 b9 U# t6 ]; x% A - 4 a1 S2 ]/ t$ L1 r, u
- string descUser = string.Empty;//目的用户
$ [ |/ b! ~% d0 r' x: r( h - while (true)
& ]# b }1 u0 T; j9 E/ \, y, _ - { Y( `. w! f: V/ K: ~( L* A, W3 ^
- if (socket.State == WebSocketState.Open)2 I( _" Y. N& q; H
- {
/ u, _7 n) M% _ - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
, u& o+ r0 b9 y" f n7 M& J - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);- v$ r- V1 P2 [
) @/ C7 s2 A. U! w, m$ l7 h- #region 消息处理(字符截取、消息转发)
5 H" {$ Y* N: \& x8 ? - try& Y) S! o0 o& t3 Z" @+ T3 X+ ^( m
- {; T9 e+ f, i) |7 {: z
- #region 关闭Socket处理,删除连接池
; h! g# Z" A0 H1 p& W7 W - if (socket.State != WebSocketState.Open)//连接关闭# ~' ~- N) Z# H1 Y ]4 F
- {1 T, \- V9 f9 u& ~5 y
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池5 h6 N+ F/ k8 l8 E0 F
- break;5 I w3 R) d* S" M/ }9 j8 A
- }
8 V6 h2 C, j1 Y8 K - #endregion, Q3 K; C+ C6 o# C' ]. ~
( b3 P# F7 E) d6 I3 g G! m- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息; j; } B2 \1 f8 E p; q% ?
- string[] msgList = userMsg.Split('|');, t, g) e3 o$ r( [& c, r' T* t7 y. D ?
- if (msgList.Length == 2)# u2 b! }- a) U, Q% Z
- { n* W9 y! R7 R4 G, y- `
- if (msgList[0].Trim().Length > 0)8 y/ J. X, _% _5 E _8 P0 E
- descUser = msgList[0].Trim();//记录消息目的用户, t- p# t3 i8 x z9 j" @- | _
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
$ W% h- h7 M$ c$ [( |1 B. s - }8 b, P, a6 m/ J
- else
% e. G% G8 l8 X Y7 F: i% v - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
" h: ~8 R2 T. b
1 L# ^: u8 ?; d3 w1 w- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线) k9 l- }! [, ~4 m- p
- {9 E1 }2 V: `4 _& M& A
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端6 Q6 v8 S& ~2 k; b4 G( }
- if (destSocket != null && destSocket.State == WebSocketState.Open)
: y$ \; ?) m) o: ?. {/ I7 D - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
4 `; a* X& O. z7 N& j! h% v( D/ c2 c: f - }" R z4 G' W, h9 Y4 D& M; F5 T: v
- else
# R5 Q0 S& @- h5 J7 Z/ Y1 F2 T - {
7 s; c7 k4 O' j - Task.Run(() =>
; i5 n1 d1 `4 [5 g7 a - { X- y4 A- M" j& w; D; N
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中4 H8 J! V/ g; ~. _
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
; H w i; y: `; V7 J - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
3 O; F9 X9 a; o u: `, Z S - });0 |6 r" f4 C) C+ E3 J# |7 A
- }
9 Z9 x! c2 l7 n: q# D( ]4 l0 M - }
3 m2 o7 _) k! {0 z4 o2 E/ v - catch (Exception exs)
/ g2 x7 y3 C/ m) z/ a, _3 z/ L- x - {
* G8 ^- ^4 E8 Y$ V" g - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
9 f/ W. z- z7 I6 [- f, _ - }
: v+ F3 B+ j. L. R* b - #endregion# ]1 O! v: u$ V5 M
- }
& U- ]" D. H0 q3 m- U' I - else- @) Q7 R' O1 N' N, V
- {
# \- \7 L" b. j - break;! y4 W% H4 E9 e' l- d+ _9 d
- }
# k. f3 R! E# j, I( v - }//while end8 ~" G/ S& I! Y3 d! A
- }
) @' }7 e/ R0 l3 D5 T( Y - catch (Exception ex). I R" J1 }' p/ w' Q5 ]2 q) N
- {2 j p9 n/ C0 [6 }! H' A, v
- //整体异常处理
" j/ ~% s/ P- G& f" K - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);" D/ E6 V+ [9 `0 p$ B. P
- }
?8 R; n' j* b, [1 ? - }% P( r+ {* L; P! O7 U# g, g
- , M5 f, T1 O3 @: |' l1 ^
5 J2 [( [2 b6 n6 C- public bool IsReusable4 m9 r9 y8 Q# |# c# E& @2 t( ~" @3 }
- {+ g) ?$ n7 i5 s3 q5 V/ ]4 b7 |
- get
! a- U! |$ w- b6 y4 g1 ~ - {. p7 R- B( |' n' ~% [$ I. D4 w- t
- return false;
; v. e8 ~) g* V - }( }5 s4 s. G5 d6 n' H) v9 x
- }4 S7 |! G2 n& S `
- }
* r6 R4 H8 J- d, Z - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
, l/ U# N! b: v4 {: I |