|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 0 E: U' Z; n) _2 o
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
) z& y+ \' p! L - using System.Collections.Generic;0 x7 B( `7 w2 z' E
- using System.Linq;7 l5 R m& q, Z0 @ c J; o0 C$ `$ ~
- using System.Net.WebSockets; n, j$ z0 y% O) w; `
- using System.Text;
8 F9 B6 R# k$ B6 K# X+ d - using System.Threading;# Z& w, p$ |2 @
- using System.Threading.Tasks;& V9 i& I3 E! ^' x5 H+ B0 W/ A4 D' j
- using System.Web;" Q3 u0 k R6 T9 ]
- using System.Web.WebSockets;& @; T5 U2 n9 N9 f9 e" D
- 6 n8 Q) R6 a" X; _7 x* o( b+ I; M
- 3 W3 D9 s8 U! u
- namespace WebApplicationWebsocketHandler/ v4 _* H& C" s# k. P
- {
3 y1 T) m/ c' v9 V9 f0 \ - /// <summary>. v& C* s( \) ]- ~( `! i
- /// 离线消息
2 S0 |: c) J( c# ^ o2 r" T - /// </summary>5 r( y& |+ V7 R/ F' o4 S
- public class MessageInfo
8 t7 L; y0 `4 J8 w( W# l" Y* N - {2 g3 s: H" G( y
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
( g4 r, i" }& }2 F' @4 { - {# m" C6 D& w \
- MsgTime = _MsgTime;
( V$ ^! s- Z1 O6 A8 _' z( s - MsgContent = _MsgContent;- O. i M2 Q R
- }# ^- v: k" L( C5 r# i* a
- public DateTime MsgTime { get; set; }
; A% j' P- G2 v: F7 w6 O - public ArraySegment<byte> MsgContent { get; set; }) [4 O3 b* z) _% ?0 B
- }
4 a$ H/ @- {/ l9 B; F' }: ]
2 n- B1 c, |7 @2 p/ D; V- ; P1 _9 m: n; M
( m" k2 O& U; l. N. v& [5 l- % T1 [( Z* [. c' I: o
- /// <summary>! y4 S1 u+ e4 T9 V) w$ y; {
- /// Handler1 的摘要说明
& n, V+ E6 X$ c; r - /// </summary>0 f3 _& o5 H( v* j- B1 P0 a
- public class Handler1 : IHttpHandler' ?5 Y8 A2 a) c0 j P5 K9 E7 c
- {
4 r! }( ?# L2 F# U6 H+ ~ - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
9 Z5 `, ~' w& K. g) s" `7 k8 u# P1 I - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
7 [0 S5 x" z; N - public void ProcessRequest(HttpContext context) U% H0 Q' G6 h- t$ |9 |
- {
6 l5 c8 u( \) z H9 s6 ^ - //context.Response.ContentType = "text/plain"; @; c; u* Q) \6 S( |/ I/ d2 E
- //context.Response.Write("Hello World");3 d# B: T5 a$ e j- Z$ J# }/ z4 l
- if (context.IsWebSocketRequest)
. p# d Q* B( j - {
* {0 ], ~! n9 o% o+ U2 m& P - context.AcceptWebSocketRequest(ProcessChat);4 g) F: }" ?6 ?
- }
: E+ Y4 B( h+ W" m; ^9 `$ j6 {' o - }
" O' ^# T7 L! N, _ - 3 ?7 G( {! Z n h3 U3 u
- private async Task ProcessChat(AspNetWebSocketContext context)
6 ]4 I& C0 L* S6 P* E - {4 d% s% O# N8 p J
- WebSocket socket = context.WebSocket;
0 m: v" ?4 X2 G5 r8 K - string user = context.QueryString["user"].ToString();
! c0 d; b, f* y( C1 X9 r - ! b/ l" w( F7 n$ [7 A6 G+ C! h+ _
- try
5 K U' k5 a- t! a - {8 W! X7 N" u) D, v& G) H
- #region 用户添加连接池1 L( z( h" S, g. Y1 t/ s2 |8 ?& s, }
- //第一次open时,添加到连接池中
& v$ S. W d) m - if (!CONNECT_POOL.ContainsKey(user))! b) N# ?/ g) {: { [, S3 `. T
- CONNECT_POOL.Add(user, socket);//不存在,添加
5 R/ m! l; L" j( H6 |% z - else
/ O; Z/ [0 m* e( z* W - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
- n7 n. D9 c7 I4 b& I2 e9 E: s - CONNECT_POOL[user] = socket;
9 q8 Q/ A) Y9 O0 ?' Y7 Z - #endregion
8 U1 Y3 F, H; H. V/ ^2 R3 s
1 k' J- F5 k4 H* @! [; G7 u5 P0 ~- #region 离线消息处理/ H# \) Y; n. g: ]; _& g
- if (MESSAGE_POOL.ContainsKey(user))
1 {0 l) m! \# R, y) j& z - {
* t% k) b2 O( E5 P1 z# O' b - List<MessageInfo> msgs = MESSAGE_POOL[user];
0 k9 G: l2 o' d$ r3 S$ n" r - foreach (MessageInfo item in msgs)
" U$ C/ D$ b8 d2 t5 R - {
5 B o7 o) F( Y6 g, `$ Y$ _0 I - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
9 [6 L! [% h0 c% s3 d - }
$ X3 U7 @ i* ~5 W1 a - MESSAGE_POOL.Remove(user);//移除离线消息
! b& C4 w- g; h3 V$ D* D$ N, t& Z - }
, G0 ~( P7 k5 F9 S2 E8 f7 j - #endregion7 V$ e3 u& @+ M& F
- ; M5 I% O& o( K; J3 B1 e
- string descUser = string.Empty;//目的用户6 m7 b: a2 G* \
- while (true)
! j, t! `7 v$ d' p - {7 y) Z1 z: o$ B' d/ \# T5 R
- if (socket.State == WebSocketState.Open)
+ t# B d, K7 D/ H1 I - {' D" S' L! l6 M/ Z3 M
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
' w! \, W+ [* H2 \6 w - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);: o2 }1 E# j- T: S) ]
5 j( C I B4 N ^ i k# V/ z/ R6 d- #region 消息处理(字符截取、消息转发)! F5 f1 `3 U% J7 W% w) C. z
- try
' l. p" v8 C; P5 `1 y } - {6 r$ @' A( ]" {; K7 s/ f8 W* r; V& j
- #region 关闭Socket处理,删除连接池
/ ^5 J8 r) J4 B! U$ _2 L( ^- t - if (socket.State != WebSocketState.Open)//连接关闭
3 E a: N& ]8 W; u8 K8 }0 `8 F; y - {; |9 m$ X6 _4 h/ F) r0 ]4 h0 v9 b8 D
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
( Z0 f; ^2 _! L* V, g% Q - break;& ~- v6 e% G" X" c( r
- }0 E" {7 p+ T) ?; }
- #endregion" V6 |+ {5 z! w+ U
3 a3 A; p8 Q# Q3 c3 v" G- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息0 E+ S( [% O$ Q% F) |
- string[] msgList = userMsg.Split('|');& {; L& {% L4 T
- if (msgList.Length == 2)1 \0 t' b: g4 F( q
- {( x/ ]" Q$ K. k6 Y Y
- if (msgList[0].Trim().Length > 0)2 \0 X' c8 _' W" V$ K
- descUser = msgList[0].Trim();//记录消息目的用户) K3 a |: ^$ ?* _% S- E
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
* ]9 l1 G9 A; `* Z - }
, w @1 S0 {# |- q8 O) n6 f, \ - else
, F! h/ S; x( n - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));6 d% S2 w( n$ i8 ]7 I/ ^7 d
- ' B' Y& [, n& a5 ?" N( I
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
, |! V0 w- a% ] - {
3 ^6 G4 ]2 @4 r u4 a - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端* z, m3 ?) Q* h" d' u F
- if (destSocket != null && destSocket.State == WebSocketState.Open) `/ K: |& o$ w
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);( n7 V- p, G0 I$ y6 ?# F6 ]
- }
+ |" V8 c' e- c+ d+ \ - else% E$ R6 J# Q5 i" X8 ^+ I
- {
* w" y$ M+ _8 {8 p! P; w/ g" m - Task.Run(() =>
6 }; @2 b6 e( o+ A4 d5 r - {
* o6 U# `) e! |; F8 p0 B - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
: z# E g* C, W; E# g$ m - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());1 L4 o/ ~+ a' d
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
C6 D M; C/ G; Y2 G9 v - });
7 M1 m/ l1 v$ S - }
9 s; E& t) |7 Y: X( U - }
4 A' w# d7 r. w7 A1 F. c: ?2 n - catch (Exception exs), X( ^, h% N/ H. N
- {
( k/ ]# N2 v ], v" B - //消息转发异常处理,本次消息忽略 继续监听接下来的消息5 ~' k' N* b' O) {. Q, d' u9 r
- }8 J+ ?: `7 M: C/ q! k, x4 |
- #endregion X" b' u$ {* Y* q, b, y
- }6 s8 D6 z+ p- n- m+ s% i
- else7 I$ I. { G1 I- r% C5 O( o
- {4 F2 h7 _, m/ j6 o4 h# E
- break;5 i+ I7 c1 l4 `# e9 R
- }5 R& X& j, K" T H4 Q
- }//while end0 V, m0 f- P: X5 t0 G
- }
( x$ n& x5 G, ]: n- s - catch (Exception ex) x( }+ `) p2 H' u$ ^& P
- {9 f- S; W- M7 Q0 o* x
- //整体异常处理
9 R, v4 t+ i2 b! D3 I! ^ - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);* U' a/ ]: U, v3 T& F/ q$ r
- }9 S7 j) i0 ]* v* K( n6 ]7 A
- }9 Y) @. T. {& l @
) ~: X! g1 Q0 j5 F- p
8 Y0 u' e+ ?, g( u, i+ f$ b/ Z- public bool IsReusable
1 @! K; ]+ O3 ^- m# O - {
) \ h* w7 }5 F' @, I& @ - get) f- o8 t: e4 @- L
- {
) Q/ O9 ^2 N5 T0 F - return false;
2 f5 M' C! k' U& U- i6 q& ~6 t - }4 }/ {) v. L* C: ^! q
- }
0 v# K6 K9 q# J' x/ f - }
; u1 Z1 O: M* a, g7 n7 }$ A+ z - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
0 ^+ Q) e# @( _+ Z |