服务器端代码编写 1.新建一个ASP.net Web MVC5项目
# V% w9 _# \7 H* Q; ^# `2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;5 P- k1 ]" o0 A* s7 U) u V8 l9 e) c
- using System.Collections.Generic;8 d+ j0 q$ `" b3 d0 z" w
- using System.Linq;2 l% I1 ^: Q8 X. e/ Z ~% q
- using System.Net.WebSockets;8 y1 c+ l9 @3 {
- using System.Text;
, p- N/ k( G0 W5 `3 Y - using System.Threading;
0 A- ?, {) E$ g, Z7 `" S - using System.Threading.Tasks;
8 R7 P! C2 n( Z0 L; a* r - using System.Web;
7 G2 c/ K; \/ X+ P - using System.Web.WebSockets;
$ s2 k% T& Y0 u5 |5 h - ' J" U f8 S, }7 f8 \: T/ f% M7 H& V
[* Q. q: `3 ^7 I+ V0 L( [- namespace WebApplicationWebsocketHandler
! V" U8 _8 s. g2 F x6 t% p - {- m2 L' Y. O7 \ P2 X6 J
- /// <summary>
9 L) R8 [3 k& u& Q9 c% g - /// 离线消息
7 O4 r2 R3 q0 U$ V - /// </summary>/ a7 j2 ~, b" O! i; e5 Q
- public class MessageInfo1 }1 k* F0 J3 z& }) @1 e# m7 z
- {
y$ p$ f% O. U r - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
& y. Q* _. |, b3 L - {6 {8 v5 ~0 d% ~( x# _6 r8 k
- MsgTime = _MsgTime;2 W7 E( C/ e Q: ?+ t
- MsgContent = _MsgContent;. [$ y5 ?' J! a: ?, h
- }
8 _ N7 X- ]; y% p# f; t. X - public DateTime MsgTime { get; set; }
5 s) ]! C* s4 i7 E9 k - public ArraySegment<byte> MsgContent { get; set; }
" n# h* h7 I$ w! a3 u - }/ |2 i1 ^, m$ X/ {' E
- 4 t" _. s' u& r0 W
0 i* p1 h9 @; I- p+ ?5 l- i- 6 ~2 h H/ [5 Z- ^$ p' n
- 6 b7 T# h+ r8 a% l7 F
- /// <summary>+ b. G# e% d, g- c( N0 s0 B+ W" d
- /// Handler1 的摘要说明/ I6 R" B4 O% q( G* O% {" E
- /// </summary>, @3 n# R; d- l1 V; G
- public class Handler1 : IHttpHandler
/ F; H9 I* _( S, a. t* u - {
) w7 C+ _; v! F! y - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
1 A3 K( X+ _7 j6 f- L2 A - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池, F* l6 W. ^" Q6 {$ |& G$ V3 r( p9 H: L
- public void ProcessRequest(HttpContext context)
3 z5 s, ^6 p! R3 V# w' B+ [# I - {
* L, ^2 Y3 f4 L6 S. L - //context.Response.ContentType = "text/plain";! t: U$ V( F! ]8 i
- //context.Response.Write("Hello World");
, b7 P" M8 l, F/ k& R7 } - if (context.IsWebSocketRequest)7 y9 k8 i2 m, T7 |* t
- {4 A/ i* T& w. Q" R8 L+ I
- context.AcceptWebSocketRequest(ProcessChat);
% r% h) Y# h: `; I5 }; Y - } 0 c( l2 Y1 o5 {: n& X- o" o
- }4 x( Q/ b" a8 D, P- X
) `" E: h# @6 X0 D* O6 A- private async Task ProcessChat(AspNetWebSocketContext context)
4 t( d5 p. S# m0 L - {
) Y' d5 t: Y# d, k' A - WebSocket socket = context.WebSocket;0 T/ }! D; j" y* w0 X$ y
- string user = context.QueryString["user"].ToString();5 n' y. `: }+ J ]
- 9 Q5 @9 [4 R, [8 h
- try
- j6 b6 R. g6 t2 b' I/ Q6 g - {: [( T+ l) R& p& E, Q/ _
- #region 用户添加连接池
" m: w& } T# c2 j, v- I - //第一次open时,添加到连接池中- L' M: @$ B. H" `2 H
- if (!CONNECT_POOL.ContainsKey(user))
6 o7 t& W+ d7 l7 T. e* M& Q- { - CONNECT_POOL.Add(user, socket);//不存在,添加
s! t+ b" M; f" S. l! Z - else
. H# q1 }$ H+ v% {# Y6 n - if (socket != CONNECT_POOL[user])//当前对象不一致,更新( P0 ^# q) g! }8 ]1 F: u& F2 U
- CONNECT_POOL[user] = socket;
( a# _8 S2 t4 }$ E# F - #endregion
' a/ d! q4 C1 s - ) H9 w% }9 q' s. W: r: M
- #region 离线消息处理( I0 I; N, J% N% F! z7 e& b$ A3 \
- if (MESSAGE_POOL.ContainsKey(user))
& \7 ]- N( b% p. d+ c9 ?1 c - {+ g: o* i3 C2 o/ H. x2 N6 [% l
- List<MessageInfo> msgs = MESSAGE_POOL[user]; Z/ R! Y3 s' [* r. a1 k2 E
- foreach (MessageInfo item in msgs)
% ]3 v+ Y4 i( n: g - { }$ K% e' P. Z; z3 t! ]) { G" ?
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
* \: {4 y; r2 U- ] B) X: v - }; L, w! f- h% T* q
- MESSAGE_POOL.Remove(user);//移除离线消息0 m7 u7 Z' [6 `3 D7 j
- }1 t/ n; B" l) J: S) X, h! R; }
- #endregion1 s N/ _! ^& m, g
1 k5 A- u( X4 l: a- string descUser = string.Empty;//目的用户6 N- t* S2 r4 _, e3 w( ~
- while (true)
5 {4 D$ B& |' J: }3 V0 W" Y/ l - {8 [' e' Y F+ r4 V8 V
- if (socket.State == WebSocketState.Open)
. y7 T; G: f; f* { U$ q; u+ ? S5 a - {/ ]; D% S* h# K3 L) x5 G
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);8 P7 k, c, q: r% q) M6 N; Y
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
$ Q& X, F/ m9 n" \1 n
) c) g% P. e x& _1 N- y- #region 消息处理(字符截取、消息转发)8 t7 k4 a' [& b
- try& A) o! [! u1 N8 w% l$ q
- {
7 y7 v) }: c7 I9 w3 h9 [ - #region 关闭Socket处理,删除连接池
' {& ^8 y& `. m - if (socket.State != WebSocketState.Open)//连接关闭$ P+ I! W* }8 g# U4 K
- {/ ?& w1 m4 F" _$ l
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
. Q3 W' w: w d5 V8 b" G3 ] - break;- @" E7 L3 V: ]& |' F2 [: O5 y
- }
8 N, T- \- h/ C5 | - #endregion, F' `& D6 D- B6 d6 S0 }$ H
; }6 U6 j* m2 s6 e( ?4 v- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息$ n' D4 j7 M2 `
- string[] msgList = userMsg.Split('|');
6 e; P2 T; l4 p7 Y4 h - if (msgList.Length == 2)
u& ?- u$ k) B0 f - {
3 {) E N+ K* x" m' l1 ^ - if (msgList[0].Trim().Length > 0)5 ]3 L* @. K# h
- descUser = msgList[0].Trim();//记录消息目的用户
( n! ]# c3 Y8 U5 y, u* z/ l - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));3 Z! A0 }7 I4 w3 j& g2 ~7 ~) l
- }8 }9 K& o. X6 Q! J* v# F9 m" [
- else
) t' A1 r6 B7 U. M3 H - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
* a; m9 t$ [" l! Q% W
' W2 w j8 J, R' V% B/ u. D" y- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线$ d# T, w) ^- N
- {/ {8 W8 \3 C! F; T8 N7 w
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
5 L/ ^( ^: p: U& V2 w+ f( n - if (destSocket != null && destSocket.State == WebSocketState.Open)1 A! t: m6 O4 E# Y, M! ^: k
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
# [+ }( n6 [; k$ c5 X - }
' h4 f# A! e1 z/ n9 X$ V - else, w j- u0 y8 V/ W
- {4 P: e7 J% G( j
- Task.Run(() =>& x7 m m0 o0 ?8 r
- {0 g3 Z6 X1 W+ o7 m
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
, |' [$ o5 Q. O, J - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());4 K8 D9 S7 h$ v O' O# ^
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息! V6 g* }& `$ S/ V6 ?! g* o; a" F
- });
3 K/ M) E# m( M+ l - }
3 L4 ^" D1 w6 g( u - }
1 X& D9 |5 _# D' r - catch (Exception exs)& J) y/ w% ^& q1 }7 c7 B1 u: ?
- {
6 x0 T* Z* F+ W1 N s) E0 D& K - //消息转发异常处理,本次消息忽略 继续监听接下来的消息( J1 E# t5 D1 K% V+ }# T3 m$ u
- }
' ?7 y: V* V" w( Z/ d. E! D - #endregion
, ~! i) g* s! X: ^ - }4 s: s' l1 u* g
- else
|# h# L. O9 u A5 f+ { n - {' k- U7 n$ [* P' d
- break;6 h9 ]7 k0 i6 Z5 @
- }) }* o/ v# m$ w& U0 X N
- }//while end7 P1 T% E0 j' @/ o+ k, n+ U$ s: e
- }/ Y* x; T2 t: B4 R
- catch (Exception ex)6 b; o5 `2 L1 u) ? A! I2 ]
- {! C, v q& r0 j! q: i6 v0 H
- //整体异常处理
. F& p4 L/ U+ M! I! z - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);6 n/ U3 Q; b, }4 j7 C! ^
- }* J1 S( [& h% J' W9 G/ H# F s) w! _% ]
- }/ b0 ]: X. J8 p; e1 V2 h
9 B$ F, c; J) W1 K9 ~' S
G, O6 V' X7 N* y7 m% A- public bool IsReusable( q) H8 [8 y! L. \2 e% x6 q
- {1 f6 y# [3 b" {1 R. f0 G2 {$ G5 T
- get, L" j c3 k5 B' F0 t0 |- u1 _
- {0 b' E- @) G) u
- return false;) H- q, U: f _ x. o" N. E
- }
) W; Y1 W$ u+ W" [: Z! O - }; B" u8 S4 D2 t% U: I
- }
, C2 X( E: B$ F+ Z& ~% Z - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
0 Q! N! E" L1 Q# @- Z |