服务器端代码编写 1.新建一个ASP.net Web MVC5项目 4 E' l# h' ?4 G) m8 d2 M' {
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;. y* W- b, @+ Q6 [ N# k5 i
- using System.Collections.Generic;
; E/ h1 m5 [9 |. O: f, e( ?9 P: E, X - using System.Linq;9 y' r) `8 n) \. |3 e0 p
- using System.Net.WebSockets;* b, y0 G* x% Y1 e% w$ U
- using System.Text;7 I$ L) S, K( S# r2 |
- using System.Threading;
2 h" l2 z* g6 S$ I - using System.Threading.Tasks;- Z) J) _$ O; \; R4 G4 V7 t" }
- using System.Web;4 R! ^" F# T& P$ ~* Y/ y
- using System.Web.WebSockets;
4 A$ \5 q& c% l; b% x: i4 B2 v
5 E8 W' Y; P- P0 K0 i. ]- H
/ {0 A' ^0 v& m5 h0 Q0 b# p- namespace WebApplicationWebsocketHandler9 I( j% |# X( A3 T% U
- {+ j$ \# ?& p: w4 G) d. P7 N
- /// <summary>
5 a2 `" z9 B% o1 k" {5 V& D: L: j - /// 离线消息5 ^$ G6 l9 L. s* G8 T; k
- /// </summary>1 |3 R, `9 L9 S% L8 m) ~
- public class MessageInfo' o8 M6 k" C2 T; ^* c
- {
* i8 w; Y Z7 C3 \2 n - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
8 G2 N0 b c; l( V8 ^+ g, t - {0 [% T p7 M6 F. j6 S
- MsgTime = _MsgTime;* q- D7 O( y5 A7 e
- MsgContent = _MsgContent;
, e" a/ Y1 T3 t/ p0 S - }
, S* ~4 R! ?6 g( v5 d& } - public DateTime MsgTime { get; set; }( n2 B( Y, N, f+ Y4 C9 u
- public ArraySegment<byte> MsgContent { get; set; }0 ]- T& m- e& K9 J3 h# Y8 c" r
- }
. \* h5 ?& G# d! t
6 `$ q1 S, D% D; p: d1 I
' P9 g7 _& @: m, \- $ b" R! M0 c* m# O0 k% T2 f
- ! _% l% s( h% D0 v
- /// <summary>
1 _ Z" s+ B8 x1 H$ ~ - /// Handler1 的摘要说明
, e. a' O6 r! x# o - /// </summary># G% ?! [/ h+ U3 s6 M3 V4 ^/ R
- public class Handler1 : IHttpHandler
, F+ q" t, _3 l, W6 d# a - {' Q* i+ x+ U' Q+ c8 I; _) S
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池+ s% v/ j8 {: K; E" z9 o( w/ Q
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池# \8 `6 X9 Z" h1 H
- public void ProcessRequest(HttpContext context)
1 r3 L- {: j# a( G- w' d( _ - {
3 ?4 H2 J$ x p) [4 B% t7 ^ - //context.Response.ContentType = "text/plain";
- c2 ]. a( q7 ^ - //context.Response.Write("Hello World");
3 v! [) E: C; j+ _5 [0 s: K# L - if (context.IsWebSocketRequest)
; m2 Z x! @6 p+ P" t - {
9 f2 {( Y2 x* N' ` - context.AcceptWebSocketRequest(ProcessChat);: k- r/ N( C7 `4 T
- } ! m. k$ _) m4 x# Z
- }) Q9 A# O# Y( I% x, Q$ U
- 3 p: C# z" z; `* F$ Z
- private async Task ProcessChat(AspNetWebSocketContext context)/ t' O% [% B: Z3 y% X3 c0 d1 [) F
- {
/ D1 y0 l& w6 N y - WebSocket socket = context.WebSocket;
% y6 m5 h9 _% i& |/ _ - string user = context.QueryString["user"].ToString();
6 s1 a* c# z5 m3 n7 l: U
, _- n. {) Z3 V" S, o- try0 G% u0 r0 F3 }& B
- {
, i, J5 K9 i$ b. S- U - #region 用户添加连接池7 V1 |/ ~2 T" q& G ~
- //第一次open时,添加到连接池中
) N4 D# l/ E# L3 `4 A - if (!CONNECT_POOL.ContainsKey(user))
/ [+ W3 `% ?: ~6 ~ - CONNECT_POOL.Add(user, socket);//不存在,添加$ t# e& W" W D) r
- else" `. r. x j* ?. r5 T5 \. k
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新' X1 y) m& n# F" N
- CONNECT_POOL[user] = socket;. J! j) q! u" ^8 l
- #endregion' F- l1 t/ h& f3 J* O
- ; |, j; ]: r8 ~( X8 d. \2 k
- #region 离线消息处理
& ` r& p' e" _# Y6 T% d - if (MESSAGE_POOL.ContainsKey(user)). k+ }4 s# {0 p/ Y
- {
3 v: G2 u% T% p1 | - List<MessageInfo> msgs = MESSAGE_POOL[user];
' W. r% I d% N( T - foreach (MessageInfo item in msgs), S! R2 s- g0 m( ?( v! n
- {
4 M* S& a, r1 u4 B( v: i6 p - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
. ]% ]& [6 j$ O - }
$ s- `. ^+ W! [4 j - MESSAGE_POOL.Remove(user);//移除离线消息9 A( I, T0 w6 B+ i5 ]
- }% v; q7 e8 v u& a. a$ `$ b0 C
- #endregion/ S$ e1 |/ [8 C8 p( S/ N4 [) p
( W9 |& R+ P4 G& ~1 J1 h- string descUser = string.Empty;//目的用户
( i+ z" `1 |+ s - while (true). N/ H' O: T3 G- f0 P7 E
- {
+ F5 J* n* v) p - if (socket.State == WebSocketState.Open): H3 m- I. A w0 b c9 q) Q
- {
1 M5 C8 m* p* E v$ q - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);1 o$ ^& ]9 c! M$ \5 D
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);9 g- T, M0 b: G6 O. o( N" k
- ' E2 T4 L) `3 a; [- s3 I
- #region 消息处理(字符截取、消息转发)
6 V, `: j% {8 C3 w2 H- O5 s+ x/ n - try
d$ y2 G; s8 H& L4 W6 d - {
2 W: r6 t. U" r4 u0 l, v. z/ Y - #region 关闭Socket处理,删除连接池# G& y0 P" c4 G% |3 |) i& w0 n
- if (socket.State != WebSocketState.Open)//连接关闭0 O# t6 c% s7 H8 V9 ]
- {
5 \. @7 W* M% b - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池6 X8 X1 r1 v1 C+ G1 L7 C% K" i# E
- break;
0 E, d& u2 E; A) p7 V: x - }
2 X V% v/ I- V2 I1 }! G - #endregion
4 x) G2 j' q% x
) _& G, j3 I) h8 i- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息+ B0 G) l8 l: J3 {- r
- string[] msgList = userMsg.Split('|');! p& h1 u0 c9 `) V* A9 W
- if (msgList.Length == 2)
/ R$ g( T3 d* K: N! f7 g3 ?- `; U- }+ j - {% H/ U/ T- j6 m
- if (msgList[0].Trim().Length > 0), g2 f* @* C8 a: a* J8 N
- descUser = msgList[0].Trim();//记录消息目的用户
% T3 T% H) A9 Q0 {5 {$ F1 I+ h6 Z# q - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));+ b2 B1 B0 _* W8 H# k: P0 Z
- }
7 m3 M2 ^, B9 D9 d+ M - else
8 K( i% m+ I6 x" u" P3 h - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));1 e; `, j) s& {6 L" Q
- $ V1 S" ?7 d/ ^
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
5 A8 ^& h9 w* X" h% j6 w/ H - {$ D/ H2 \% [0 M* F$ E
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端6 O6 A; o1 D& J6 }
- if (destSocket != null && destSocket.State == WebSocketState.Open)
$ o9 {- {7 n, C# |2 A- U4 g - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
$ e, D- ?9 M* ?% j, p) t# T+ @ - }% W5 R/ {7 v3 n% c) ~" Q. x3 s0 R
- else$ S, S7 Z7 D/ f4 Y% F6 {* B7 I7 N
- {$ {# |1 M, A) q8 |
- Task.Run(() =>* S# S) O) a7 Z1 X8 J7 t
- {7 Q3 i- X$ E. e- C' i
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
$ ~0 W& o9 ?4 n( N$ I - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
# e' @9 o0 A) Q9 m% o5 x - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息4 p4 P% P* ^- w" U, F1 T2 C
- });
* x! i0 Y3 a4 k0 Y$ a1 d - }8 C6 W9 o" M9 u. ~2 X% T
- }
& \- g- X8 y' J! i - catch (Exception exs)
! U+ `+ ~3 m1 v! Z" a0 W; b: P - {2 l& Y) Q- n# L: o3 c4 ^0 t$ l
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息6 {: j9 P& r$ O
- }
5 t" D* v# i7 e" R% r6 G% u - #endregion
" N$ U( I- w u, u- x c. W: E - }
/ L+ Q- J& `! u2 }& I& W% M- o( B5 @ - else% l! A1 ?8 x8 a! n
- {5 H. E9 q# E. t0 q, @& h
- break;. x# s8 W0 O2 ^& e8 R
- }
3 i" B4 \5 M, |, c4 o1 V - }//while end6 y3 J1 l8 X3 X1 |# L8 j7 ?/ L! q
- }4 U3 n. i& o1 s. l T- V5 F- L
- catch (Exception ex)) O7 t. D l1 ]$ U
- {0 w! N; E- f0 q" P/ |
- //整体异常处理
7 V& c l. c" P% n" ]' \( y8 {1 o - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);( P& y+ z( E6 E. M
- }! m3 g: p3 e8 V& U& l
- }1 Q2 k7 P1 W' O# r/ {- F8 p
, o$ l; ?$ u/ g1 }8 l2 Q: w
* q) ~, I( w, Z- q( R! b, U+ `# j- V) |& k- public bool IsReusable
1 {# p; \- v: _( D- e: p: J - {
; L" g4 `. g( ]0 F: ^0 ?/ I - get: t4 K, D; ?: W/ H
- {
2 f8 @; x P2 {& Z# V0 ~* n. b - return false;1 |7 v8 u3 i4 i5 k6 a: a4 W
- }
3 I2 D. c1 j6 C5 y; d - }/ ~: b; I* l% g4 @
- }
( z: }0 D, j! b0 b+ }. q: H - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
% a/ ?- u) S: q! A$ b& b1 f3 { |