服务器端代码编写 1.新建一个ASP.net Web MVC5项目
9 Z/ ^3 d0 O9 R- s2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
, N% @$ x" y; E1 Z! y - using System.Collections.Generic;
! S$ r: w, U# x( m0 ` - using System.Linq;
, [! h U: g5 b - using System.Net.WebSockets;! O8 J. i% K$ d% T+ f: |7 `% o5 G
- using System.Text;" a7 X6 T( ~2 ]
- using System.Threading;9 T; D+ [' q. Q. j- g7 X
- using System.Threading.Tasks;
% m" E- B; v8 R) K1 p7 B- q+ ^ - using System.Web;
& r; m# N6 b" m0 U5 {; d* V - using System.Web.WebSockets;+ y$ @. K q1 r! U! }- [
" c v# m1 ^! W3 e9 c- ( a" Z1 H" C# L+ j+ O
- namespace WebApplicationWebsocketHandler' A8 a5 g1 u/ M$ |. y8 ~) U, o) k
- {
0 A# x' |- A5 }# Q. ^" n7 H - /// <summary>
; ^) h$ m% Q. Q0 b/ ? - /// 离线消息/ Q' m' F" W0 H+ S# ~6 [, p
- /// </summary>
/ j; [8 C4 S) W; u - public class MessageInfo/ L d" g2 W% t- S% m' Z
- {( [- X/ M; M; t1 p1 L
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
9 ^% R3 L( T2 |' S - {& X' l( M! t2 }7 P2 @; ` u0 C. Y# f. x$ u
- MsgTime = _MsgTime;
/ \7 |; O; X; ]4 }3 E - MsgContent = _MsgContent;
/ N4 g* f- s r( g - }0 v0 b3 L0 p& X7 |
- public DateTime MsgTime { get; set; }. A: a* r+ r9 a* u5 g
- public ArraySegment<byte> MsgContent { get; set; }' G+ L7 T$ M* a
- } f2 I7 \) p! @6 i" J
! ^' V& s1 O4 [: e: j' p$ M* c- ( r/ z4 J1 S( b& ~0 c
' b/ A# |) ]$ }- X& i; P
3 q, v* A. v0 o- k8 S- /// <summary>
( S. H: x% y4 ?& x) k! O - /// Handler1 的摘要说明6 L" F. Q" S8 D4 [
- /// </summary>+ F2 f- z1 q9 c( p" `# ?5 ]+ n
- public class Handler1 : IHttpHandler( C# x& z- ^. x" W
- {4 f0 @6 A6 P. ^8 v/ ?; `% `. J" v
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池% { U4 B$ Z( r. b2 {
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
' E- C3 `8 q+ @6 L$ ] v - public void ProcessRequest(HttpContext context)/ d+ T2 s: w) ]) Q7 g
- {
1 B- R5 k) @3 j4 |6 e u - //context.Response.ContentType = "text/plain";
. L3 H( C3 |* |1 J, Y; }# @ - //context.Response.Write("Hello World");
8 K; {5 ]4 X7 F. |& t) ? - if (context.IsWebSocketRequest)
" W0 B3 q: ^+ W- ]; a - {
- ]% L' B3 ~/ y3 d - context.AcceptWebSocketRequest(ProcessChat);
- E( n: ?. G8 ]9 L, R - }
0 ~/ c/ a8 W' W0 J3 T. \* v8 g - }
( M* P. U: W0 v t - / I6 i" K' U$ ?7 v2 b2 r% C
- private async Task ProcessChat(AspNetWebSocketContext context)
! E9 \& E6 q! o; t1 a9 T; H - {
5 C$ D& K1 {9 U; h+ Y - WebSocket socket = context.WebSocket;
+ }, L, Z& _" Q. | - string user = context.QueryString["user"].ToString();
, p% \4 ?6 b( c, d - ) I3 g4 t- \ a% W3 |( _
- try( h. ?3 `* r7 E$ T, V( I3 Z
- {9 b2 j' D/ @, t$ ?7 W: {
- #region 用户添加连接池! E7 s# l9 s4 [8 X
- //第一次open时,添加到连接池中4 _7 o, w8 N: q* N4 s% Y1 K* g
- if (!CONNECT_POOL.ContainsKey(user))8 `7 R# j S: ~# F2 w
- CONNECT_POOL.Add(user, socket);//不存在,添加! H* e& K" y6 t$ _7 f2 C
- else
" }- ]+ q) c; Z - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
/ |+ k+ m7 N& Q" M" p6 `4 Q! [$ I C - CONNECT_POOL[user] = socket;4 f4 c/ S# M" t3 D# j% h
- #endregion
9 ? T( |, j4 ]% u/ `8 B; s: `
* h+ e, I1 K0 g( t* S" N: Z2 e- #region 离线消息处理& E" c! D$ c* t. s: _
- if (MESSAGE_POOL.ContainsKey(user))
; {& h3 m4 v7 t3 a! e6 D - {
; `3 r& I0 ]8 x - List<MessageInfo> msgs = MESSAGE_POOL[user];
9 P5 G% a7 u) X) w; o( t+ O - foreach (MessageInfo item in msgs)5 Y6 D I# u1 v' M& X' p
- {- v9 S5 m7 b1 ~' m2 g+ ^
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
: R3 B: P" F. K+ A, s F/ | - }
- {8 p: E- h5 p7 D - MESSAGE_POOL.Remove(user);//移除离线消息
- ^ z9 i1 e/ {1 n - }
5 I% @( f, [" Q/ K - #endregion5 f) B) T& E* J/ P# E
3 C3 n1 f% s8 O. s f) n2 u- string descUser = string.Empty;//目的用户4 o9 J) e+ G: C- {* L7 }( ~3 o' z
- while (true)
# j" E: f6 g2 B2 l% A) S - {9 |; N T) v0 ]) |4 \0 o5 }5 f
- if (socket.State == WebSocketState.Open)
$ a- j ?4 D% j2 n2 z0 l - {- D7 c, t( E3 K) e% S
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);, n7 p1 G1 N/ c9 b2 j8 O( {. W5 I( d
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
9 t8 U y& g/ d/ } - 0 I- Y0 i* c8 S
- #region 消息处理(字符截取、消息转发)6 F# t5 f9 m4 S. y' o: \8 E
- try
9 M* E! j1 i! j1 q5 J4 d) T - {$ u! v# C( ?$ |8 \* x2 r- M6 L
- #region 关闭Socket处理,删除连接池
0 q0 E1 K# c4 y/ n) w - if (socket.State != WebSocketState.Open)//连接关闭
" }" c- x) P$ h2 x* X6 l* q$ r w - {
2 P7 h, R/ F6 h2 \. C5 U5 D - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池! l L$ j6 J8 f1 l) C
- break;
* X2 [5 ~7 V6 ~; m - }
. ]+ g" e3 ~6 h- T. R% h - #endregion+ f, N* @4 d% Z* g$ B% n0 X
- 4 c6 j1 O9 }; U& |3 q |, A# p& B
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息: k% c8 P- z6 Q6 q' _' k
- string[] msgList = userMsg.Split('|');
, ?, d8 ^) q: A- X* Y( f - if (msgList.Length == 2)
" i: N+ n6 O1 Q+ f* S4 p9 _+ J+ W1 L - {0 y$ y. j! H% _5 j9 L! ~4 \7 c
- if (msgList[0].Trim().Length > 0)
- ?7 K% q A4 V' a( N - descUser = msgList[0].Trim();//记录消息目的用户
; S6 P* L7 g: ~& C0 ] - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
$ E3 y ^7 ^9 T/ }8 O$ d4 i0 O - } U+ F* h) h+ \! b) V, x# D9 r
- else# _+ C4 ]# m3 ?9 n1 a
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
9 y' y7 n% u8 ]3 y
" ~: t' X [1 a& k- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线1 o+ n- g- [' t
- {
% o w" `+ Y2 d' K0 f - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端. c+ b# c5 _$ q( {2 \/ X" c
- if (destSocket != null && destSocket.State == WebSocketState.Open)
9 S+ O0 @' V6 K! @ - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);( @! n1 T* l! m$ }; g4 c
- }
- x1 {" W1 X+ H. r - else
% \7 ^" ?3 X: h2 k6 | - {5 O9 U1 b( {4 O/ x' R0 T) K3 d
- Task.Run(() =>" R; u5 K5 [0 z% b% t% N: }2 f
- {
) n8 C# J0 g5 U* y) { c# t0 x. |5 N - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中9 a7 r* O- z" d' e. J$ o; r5 g
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());, C6 ]( C2 V% F
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息* x" e$ v3 L9 ]! \9 J7 _7 a
- });/ l9 I B- ?1 ]9 C4 z) x4 z; Q. J
- }
8 C3 }6 Y. K# i4 J - }0 _/ O- G& F/ |. L7 `5 \7 a
- catch (Exception exs)
9 \+ V- F. l* [% f& O - {
( \, g, i9 c2 R+ o) h( N) l - //消息转发异常处理,本次消息忽略 继续监听接下来的消息' K6 j7 L- X x" ~5 I* G) b3 l
- }
) r/ P. h+ ]( O+ {# i5 P2 w - #endregion0 K F8 U* ?8 a3 L n$ ?
- }9 {2 d' _ P8 {8 m( i0 ~, ^. a
- else2 g7 T c' n# P. i" q. C( g
- {* }; N4 k8 ^# q |3 A+ K* o) G
- break;. y3 \* z& o) o6 |) v4 ~& h5 }9 \
- }" u7 u" N, \: u. e9 }" Z
- }//while end
+ B, R: M$ J1 C4 O - }( c# N( ?* ?: |4 d9 L
- catch (Exception ex)
9 _* M; G A0 r6 m* S# I& y# i - {/ s( h! y" I" D6 T+ \' }) k
- //整体异常处理
8 [. v! o. }- f# X6 C - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
: ]4 e- h9 e- N0 _/ A - }
1 p9 B7 v, b2 C0 ] - }* {- V0 b$ v: Z' B3 L& \+ [; h4 M
- . v7 ?! \8 x. O r; @) w/ ]
( i+ n# D9 X( `5 ]- public bool IsReusable
6 Q+ N3 a) o+ v, ]- ^ - {
; |8 s+ B6 a; J - get' V1 Z! E3 l& |* p+ L, }
- { X9 r# f2 o7 |( V
- return false;
/ q& K2 h# o. d/ G( R - }
) u7 t# V' S$ a; j( o - }
. H7 h0 a2 Y( {0 N( `; w9 \ - }
* T. b2 }" L8 w) s* T2 o% A" u( U - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
( ^ k: A2 C& X6 r9 I/ I7 B |