|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
c$ }- I [9 R+ v( a/ O2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;0 M9 Y, w2 ~ w( X
- using System.Collections.Generic;
5 e7 `* ]% G8 O9 u - using System.Linq;
' j2 o; h n& E: j7 D2 A - using System.Net.WebSockets;) B J( O" y3 {0 f
- using System.Text;
$ R. d! L" `! n - using System.Threading;- l+ v9 p2 }% B) n9 Q. i
- using System.Threading.Tasks;- |$ t% {( l2 N4 Q0 ?
- using System.Web;" F" Z: P+ v- p5 I ]0 {) {4 V) K6 Q
- using System.Web.WebSockets;% ~+ r& n- O7 ~' b3 y* U
1 Y( X* |* L1 X6 t& e! z% T1 U' p- 9 o8 z1 u; U9 t& t* v) B5 z: O
- namespace WebApplicationWebsocketHandler
4 l( S/ X) A4 i9 Z( b4 m! i4 v) t/ } - {
& ^9 j4 c7 d' |, z5 Z1 D9 g" x - /// <summary>
8 N) p' U) X6 s( ^* p/ t2 J - /// 离线消息: O: F/ u1 d4 P
- /// </summary>
& g, g. O b! X - public class MessageInfo6 u% O8 m+ I$ n0 L& g s
- {
; X9 ]6 X% L( u% q& @ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)/ g2 X2 _4 G5 |" O |1 ~
- {& o: B8 n- x: u3 k# k- e
- MsgTime = _MsgTime;
6 o H5 \# j6 t: o' t0 y2 l - MsgContent = _MsgContent;3 g, q b2 X) F U' z6 i8 G$ ]1 T0 \) d
- }" t( Y9 p8 v5 O3 p3 c/ D6 z9 B. a9 }
- public DateTime MsgTime { get; set; }
. S9 W+ s! j$ z - public ArraySegment<byte> MsgContent { get; set; }" X( { c( m4 c, s. S* l5 D# N
- }& O/ f& T) O1 @# h$ M, B( \
- + b2 F+ f1 d: `9 g# D
- * D4 v7 U( k* C/ E5 j
# P& [; A/ U4 y& [% N- 3 ?1 v6 }# z% r" s3 G% x# e
- /// <summary>
) k! D$ o3 R& ]* x, F8 K% t - /// Handler1 的摘要说明
5 v9 e& K% o5 A# U0 j. {. x - /// </summary>
9 ~4 q/ j9 a8 [0 b9 {; C1 n) ^ - public class Handler1 : IHttpHandler& O6 F+ G% |# X$ v( i* S' y4 O
- {
% k# I7 ~" [$ D: Q - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池$ {* B8 R j1 m$ p1 l; @
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
- j8 _! i3 h( _5 v/ K6 C. [ - public void ProcessRequest(HttpContext context) d2 {' Y1 P7 m6 k( z5 ~2 F
- {
$ r$ H0 f k2 J9 \ - //context.Response.ContentType = "text/plain";
( G8 j0 X1 o. H" k0 W: N - //context.Response.Write("Hello World");
- }$ T! S+ H" N$ D" o% H - if (context.IsWebSocketRequest)
- F3 W8 _! A' e+ Y8 V4 j( O - {
9 r- U0 L$ b( k2 n# |4 |8 n& d; S - context.AcceptWebSocketRequest(ProcessChat);
& R( r8 P1 g! L l2 p! V/ w - }
$ \8 J6 l9 F) {: _- ~# \. w# N/ m - }
+ O4 \1 {$ P: J( ~2 u1 P
5 V1 e& k) ^" }" _7 M! R- private async Task ProcessChat(AspNetWebSocketContext context)
1 c0 b3 O5 V* F& t7 y9 `( } - {- I5 t ^, g# n( |. J+ g8 n- u
- WebSocket socket = context.WebSocket;
* ]% ^2 K! O# K - string user = context.QueryString["user"].ToString();! z5 J+ u. ~8 Y/ F' F6 j" P0 R' F
0 e3 b* e# C7 a3 f1 \- try* V7 J( A0 b3 J' M, F
- {
3 K# H+ D& z- n% G - #region 用户添加连接池
) m- S$ K4 H* q& k1 W9 a - //第一次open时,添加到连接池中
6 N7 J8 H% i7 Y) L5 W - if (!CONNECT_POOL.ContainsKey(user))
. r: ?$ _7 P/ Q5 C - CONNECT_POOL.Add(user, socket);//不存在,添加0 w; p* o3 ^3 X) c% J* C" R0 r
- else* w+ \6 C/ _4 n C
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新2 T3 {. W! W* a2 G
- CONNECT_POOL[user] = socket;. l0 {; a C% n% t* z0 k
- #endregion r2 O. y; D5 @. K' p/ Y
' W6 p: r9 ^9 W, @$ b- #region 离线消息处理8 t* o. c4 I- L7 ], J; O% h9 O
- if (MESSAGE_POOL.ContainsKey(user))6 X b9 r0 G* o1 G0 b+ c4 `! o3 E
- {4 W# r2 q% W2 {+ Q3 ?
- List<MessageInfo> msgs = MESSAGE_POOL[user];
" T1 u7 V1 _- ^- d - foreach (MessageInfo item in msgs)7 O$ p) J, ^1 r( V
- {% V1 J& j/ e4 R
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
8 l, \ f' ^4 L/ c' q - }
2 ^, Z/ w* `! U8 W& H8 K - MESSAGE_POOL.Remove(user);//移除离线消息
+ ]4 B1 y# ^6 \ - }
8 h( z2 W/ U+ R( y - #endregion
: [% {2 r% H/ ?* s( A1 ~0 V+ b
) t8 q& a; ^0 m1 U- string descUser = string.Empty;//目的用户
. Q" v! s) Z* n& u9 b - while (true)7 b9 P4 ]8 T! U/ u" n
- {+ _8 d3 J! C8 G- L! j3 ~
- if (socket.State == WebSocketState.Open)/ |+ q1 O5 J, i0 V' V3 W# @4 O
- {' S% Y* V: V2 q# p- }8 b$ h( m/ E
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
4 D0 Z2 F2 K9 C) j, C/ V - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
( q5 L6 X: @4 \, Y# X. m
& Q: I! x# p6 {! r/ d9 D: ]- #region 消息处理(字符截取、消息转发)2 |' B# K' D5 h/ r
- try) I' C2 h8 n/ P9 V: k. \
- { B& S2 W5 q/ i' ]
- #region 关闭Socket处理,删除连接池
7 e) H" C" a" O* ^# J - if (socket.State != WebSocketState.Open)//连接关闭5 w4 X+ w3 B/ B) _: O) _9 V. ]- e
- {. J: f7 A6 V4 @! m. `& Z- V
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
0 l) T2 E; \8 r" J9 |2 V9 M& F - break;
' V+ }: B" m2 z% P - }
2 o8 R2 ?5 M: _- D0 Y - #endregion. r" k9 r, h" K' S) ]8 X
- 7 P" h" Q7 K: M9 B H# ~! c
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息3 z9 j7 @' _9 C- ?
- string[] msgList = userMsg.Split('|');2 Y w; ~3 {1 ~5 `7 ?3 w8 Q
- if (msgList.Length == 2)7 a1 V6 k L/ l
- {% l- G: E6 I* p: m1 p1 O1 G
- if (msgList[0].Trim().Length > 0)0 c. ^6 S7 a5 K0 R# _
- descUser = msgList[0].Trim();//记录消息目的用户9 Z% U; a# e! P* @7 C
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
' \8 c/ y* A" ?2 E - }( t8 [7 R8 Y% r9 [
- else' g3 ~: c9 _1 J1 l3 a
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));& f! V4 E; j& L# {0 @, t) I4 Z' |
- Z6 `) C0 l1 e1 x" ~$ }- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
; r: h: V# ?0 x, ]1 s- x( J. Q - {( I8 K+ V* M. ^5 K3 f6 g
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
* Y. |* A, a+ j0 E - if (destSocket != null && destSocket.State == WebSocketState.Open)7 }4 k8 h6 l8 |) |/ z9 Y: N+ I
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);0 U' z* }+ m2 r5 W" B
- }
; b' `' I' N& K A. k- C% R j! A - else: }6 R7 ?- B1 D; h
- {+ j& @# ~8 W3 ~. Q( O2 D! x) i/ S
- Task.Run(() =>2 G% l9 P# \3 H4 Z6 @
- {4 L# o) G& n! R. g* H
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中( `- y% I% m5 k7 I# |. N
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>()); u( a' K/ V e. p( ~
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息5 u+ T2 U& G, Q) V2 M; d7 H7 A& S8 G
- });
8 L7 Y2 i1 N! T& U4 Q6 h - }+ }+ D1 P" N! R
- }* v4 T+ i0 y" z
- catch (Exception exs)6 @% |8 X2 j) ?1 U
- {
3 K/ L) p/ r9 _ - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
) ~; x" G" W& v. E0 I2 @: d; Y/ K+ s - }
j; T0 ^; x! }5 r" n, O - #endregion
/ N9 I# R' `2 m9 v9 f( T - }0 `( G; n K. z2 y' h! a+ Q0 d
- else
) h$ R# o5 m/ R3 a9 @/ a - {# s, R5 h# L5 H, d
- break;
4 P8 j( D; [7 S* T/ f - }
0 t7 P$ t5 c' B' x2 s" d - }//while end
( z. l) j8 }. Y( a; b - }! A6 Z2 m. I, u8 W
- catch (Exception ex)
# q/ S, v: h, f* C b, M* l) k - {
7 H {$ T- n& P2 C - //整体异常处理
9 v0 h+ Y h6 e- j, j( F - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);; a+ a% D7 }2 G
- }# h$ Q1 { V! s8 A% R
- }
1 {3 g) H+ ?# J* G: Y5 z
& d8 s* [+ B7 Y0 F5 n- c% p
0 k0 g9 T3 ~9 S- public bool IsReusable2 H9 F4 t; O K( w- V
- {
9 a# Y7 f7 ^6 D5 U: ~; r - get. K& e( B5 K8 D
- { G Y2 U+ m! v9 G- f. p
- return false;7 ^6 W/ A, S# R, R& p: K
- }
3 h- ~+ `% z" h6 j+ A* T7 L - }* u, \8 J \# v; _2 K
- }
* s" _9 H: S9 T - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
# d1 a7 a* L9 n- E, I4 {8 G1 c6 Z |