|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
2 x0 l$ S6 \( x1 i2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
& j- {( m0 S8 |* I- M+ v& E3 Z6 V, e - using System.Collections.Generic;- z9 Y1 g. S) K5 m/ S
- using System.Linq;1 u2 L" m9 R5 R7 l/ V3 l0 o* [* \8 g3 P* O
- using System.Net.WebSockets;% _. ]9 R& m+ d r4 p h0 s4 x0 J
- using System.Text;
3 i. C2 w" ]! X' B( J0 @3 { - using System.Threading;% m- V9 H! S1 S/ f
- using System.Threading.Tasks;
j! o+ D6 v+ T' D2 i* k6 E: Q - using System.Web;6 t- j, a- J6 j; \" m7 K
- using System.Web.WebSockets;: Y2 A, H- P. c9 V7 I$ a8 k
- ( G5 X9 w" k/ k: {- A
- ( ~0 D+ ~7 l' \4 X
- namespace WebApplicationWebsocketHandler
! J% V; c" X9 o4 H/ Z6 U - {
2 i% }7 K2 |; o. T - /// <summary>' n% L/ I0 m4 x6 R) ?+ F
- /// 离线消息' K! c1 g. p G) h& Y
- /// </summary>" {- w5 i4 y: s5 F
- public class MessageInfo
' p6 [1 l; k$ U. r+ _4 z; @9 {, G' D - {; U- Z5 E# J# x1 j4 {. U
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent): _. l4 f& u% O: g* S0 B& n$ |$ I
- {3 g) r2 `7 G/ Q' n3 k J9 r8 b: B+ ^3 f
- MsgTime = _MsgTime;* t4 Z. G2 \1 l# d' v
- MsgContent = _MsgContent;& V% E) N+ w* M! l" j v' Z3 G# H, J
- }
# d* _: h( d" P2 a7 I - public DateTime MsgTime { get; set; }
3 j" t/ Y3 g- n s0 Y+ G' I+ G+ ? - public ArraySegment<byte> MsgContent { get; set; }3 U3 |/ U/ D5 |
- }
b, f4 H& k m
( a8 Y; g) h8 {- & }: e" s4 |' L/ l0 [" \, o% o
- # f" H/ I9 Y" x/ d: l" B) F
- * Q" s0 ~% K; K- @
- /// <summary>
! T2 z; y5 s. p. t5 ] - /// Handler1 的摘要说明- `5 D- R8 e! n) P
- /// </summary>
# {8 l' O6 F! g9 @- L l - public class Handler1 : IHttpHandler
( G. T% C6 L" c" r2 o+ M( Y5 G' D - {
: P% _+ u3 n1 x4 I" o+ I - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
! |$ T3 b( g( P: J5 d/ | - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
& b, P& | _1 G% ?! }! w% Q - public void ProcessRequest(HttpContext context)
0 h, H" E' a6 I, q6 T# D `6 R- U9 C - {: g' Y" N" k( I, G8 L( @
- //context.Response.ContentType = "text/plain";
4 h3 W/ D% r3 `) |- v. X - //context.Response.Write("Hello World");" A, [' S, X$ ~8 A
- if (context.IsWebSocketRequest)5 q( ]! J, A3 m9 ?
- {. [9 B2 J+ G7 r1 t. g8 M4 S
- context.AcceptWebSocketRequest(ProcessChat);
8 B$ G5 b8 z6 M9 y) a4 J4 @$ r- S6 Z - } ; U2 y$ v' J; O, t' _
- }2 P4 R: t; V9 b& t: O) x! D
3 C6 R# D; Z" W2 x0 [: i& p% `! _& d1 ~- private async Task ProcessChat(AspNetWebSocketContext context)
1 }7 K# D% f4 S7 {1 y - {6 P* a7 \. u v
- WebSocket socket = context.WebSocket;
4 y# d6 v3 T7 B6 Y$ D; ~- h - string user = context.QueryString["user"].ToString();2 o& `7 |. Z+ \* b$ A8 e
- - P; A5 u8 w7 S: z/ x
- try4 c6 @% Z) B0 [ b( Y% n
- {
! n5 Y2 [6 q, i0 P X" o- |6 u+ s - #region 用户添加连接池) m3 R, Q! l, ]9 n6 S# `
- //第一次open时,添加到连接池中
: p, i0 e) d( s% e - if (!CONNECT_POOL.ContainsKey(user))
$ c/ M" ]' p4 p: Q( |8 E - CONNECT_POOL.Add(user, socket);//不存在,添加6 e) O- z# g2 z: u( a& s% ~
- else9 `) K( s2 K9 h6 H
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
5 B% P% z5 ]% u9 y8 ? - CONNECT_POOL[user] = socket;
9 [3 X3 _; C9 z* b8 o ~, Y$ l' | - #endregion
. Y& |7 u/ q" e8 O T6 ?
5 M. g! z7 t5 @1 U: l8 v- #region 离线消息处理
# a% |" R3 ^, ]* X% B8 C+ A" Z) |6 ` - if (MESSAGE_POOL.ContainsKey(user))
, Z+ f- U. a9 x - {
& p' M' e7 }! X8 @5 L - List<MessageInfo> msgs = MESSAGE_POOL[user];6 R1 s% i& s% f
- foreach (MessageInfo item in msgs)+ m+ k. c! ?# I' U: Q$ k
- {4 }; c( C" ?& H& ~
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
' A4 ^, X4 n0 U3 ?& _% e& h$ H4 _ - } b( Z: a& y) C# C& ~
- MESSAGE_POOL.Remove(user);//移除离线消息. h! X; J8 t. I! [
- }& f& }0 c$ Q1 d$ k# Q
- #endregion
; _* y) a5 d" r. q1 n - 9 I& f" P. X( ]* x5 D- {
- string descUser = string.Empty;//目的用户! t/ @9 C, Z3 X
- while (true)
$ k9 I$ z; S2 k: I - {6 G. j+ C( E. Z( c* b( K- C0 S
- if (socket.State == WebSocketState.Open)* p+ Q6 j2 l" n; M) R
- {
9 r# i3 n( ~8 V5 } - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);( \$ M' o6 q; |: j: Q; Y8 c$ y
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
6 ?6 s* f) S$ {: X0 r, \$ G - " N+ F, _; |' {
- #region 消息处理(字符截取、消息转发)5 Y- x" O' E* q, m! r+ M
- try
/ i7 X `) |: q: h7 m - {
* H5 ]# W3 \1 a9 Q- k - #region 关闭Socket处理,删除连接池% F2 r, p& b0 F6 y' h F; @" D! O' y6 _
- if (socket.State != WebSocketState.Open)//连接关闭: ]' g0 I: X: L
- {( |* O$ s/ N; }1 L S
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
! x1 V3 M- e( c) V - break;6 P' \" Z: d/ k5 k! U- E
- }% \) b6 D; z0 F6 U1 r$ u
- #endregion
) d/ ~7 H% q8 N
7 E- y4 U2 M, T8 r3 K4 j- |6 R w9 z* h- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息( ~5 d, y$ K1 c' ~7 J
- string[] msgList = userMsg.Split('|');
8 {$ s' @; w: h - if (msgList.Length == 2)
* \7 F6 D% x/ p - {
/ {. t5 T% |" V7 z- ^- X1 P$ f3 h" B - if (msgList[0].Trim().Length > 0)3 E0 ?) ~* p7 l; g! b
- descUser = msgList[0].Trim();//记录消息目的用户: z; D. q( w+ x+ f
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
/ h' b9 F1 H' n6 V - }/ R. F8 q" S* o" Z; P& Y+ B( |
- else5 f8 J6 ^( j0 b
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));% i+ O! Q1 R$ u; P5 H' t$ y6 i
" N* f7 d2 p4 i* a- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线' Z9 ~, g6 _2 m$ p( [+ u2 D
- {
& i, R# T2 k, N$ D6 ~' D - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
+ A' x2 H+ u A% k - if (destSocket != null && destSocket.State == WebSocketState.Open)( Q& {6 D! b N( ?
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);, k& N0 j0 w3 {3 i1 L2 e$ C
- }* `; Y0 W: c9 E, O; x
- else# g& h9 T" Z* k2 G
- {" j4 }: \) V/ C+ K- A G0 L }* i) p
- Task.Run(() =>
4 U+ ] G3 o! J6 B - {
9 R9 N. u) V$ q0 a - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中- Y& p$ K* z. t( T u8 Z A, ~
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
/ y/ b1 _+ x4 Q! D - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息7 A7 r& P( M* C3 h2 I- e
- });
; n' L E0 {1 g7 m - }: a9 R/ C4 W5 {- m4 _- H
- }
/ @7 A; p0 p# G9 v - catch (Exception exs)
* O A/ q) S% ^) a - {
0 A9 q: A. X9 U r3 m" _ - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
5 y8 p. E& F( Z9 P$ X - }
0 o; Q( h* B* R! K W, s7 c5 D - #endregion& P8 i- X0 ]! `( x% l, {
- }3 W( F) x" ~; S) A/ w# O# ^
- else2 d& }' i3 \5 e' G) b4 `4 P5 d
- {9 W, E1 I( o! G2 ~# ~$ s" {
- break;
( r! s" {. d: C, ~ - }/ @- n; F* }( H% [
- }//while end
& f+ `. ^! F- _) b - }
* m# o! R O7 }' n* `9 i - catch (Exception ex)6 U O; G+ P9 e. I
- {6 J. R; v; k9 U$ _( g
- //整体异常处理
$ ^- H% @/ Z! u0 ^. f6 ^! I! s - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
% g/ Z" X3 v( V0 Z - }( s& ~! z4 o" _ g
- }7 Y4 L6 j( O. [
* u! X! |1 P/ i7 c2 s
( b) o8 D, ` Q8 `- public bool IsReusable
& H: {% e+ L6 q# S" D - {
$ O8 |+ V( G, d% `' a Z - get, H' [$ J0 X: l) |
- {; x1 S( e$ h* w! h; q5 t
- return false;
6 G; T, O1 Q6 p0 H7 \3 B& p q. m - }: z% x1 h+ ?, ~# R# R
- }7 v8 \7 \% k8 R; W3 b
- }$ w# y5 j0 i. E
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
. L3 _' u# d# T9 ~0 _! G4 n' N W |