服务器端代码编写 1.新建一个ASP.net Web MVC5项目 $ K0 d% B5 U# S& ^; ~
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
2 t/ B( m+ ]" e I - using System.Collections.Generic; _7 D% X2 @1 c/ d# s- A. z
- using System.Linq;1 Y! C8 H! v* a4 r; C
- using System.Net.WebSockets;8 u$ U e4 R* u8 T4 x
- using System.Text;9 b) X; [3 n4 J3 [ f* Y
- using System.Threading;
( a" ?1 Z9 K0 ?/ U& W# n0 s3 g1 h0 ] - using System.Threading.Tasks;
% G* Y- H" Z" J% [$ t6 j - using System.Web;. R* @7 J: h" V) K) e
- using System.Web.WebSockets;6 M0 {7 J! j) B0 x$ [" S* A
3 @: e( ~! f5 [! ~& i- 7 Z8 ^9 H1 R! O \
- namespace WebApplicationWebsocketHandler
+ r3 [9 w( T q3 z% h1 a. m - {
1 ?7 C0 U, G1 _# v* ~. ~% q - /// <summary>
; z7 R- u3 _, I% ^ j% H: c - /// 离线消息7 c' e7 F& o& s+ c0 U* B6 @
- /// </summary>
& g; B. p; A- Z6 D - public class MessageInfo8 D/ j# i9 h2 T$ C" O
- {
& V3 e9 @9 f$ I) ^- U& \3 J0 _ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
! A7 V2 h3 Z. c. t, x - {! I# r$ |, B. H% X5 p+ K
- MsgTime = _MsgTime;
$ r1 J3 n/ Q9 Y6 v/ L( h8 ~) B+ p0 l - MsgContent = _MsgContent;; }/ ^( @" a! X% z' T6 [
- }
* N# u1 h7 v% K" v; J* W - public DateTime MsgTime { get; set; }
1 k3 K. [/ Z# K! a6 E - public ArraySegment<byte> MsgContent { get; set; }0 D3 ?! l4 `6 A a3 D
- }7 }7 _& Q% {6 F! b; w( p
8 o. i! {( V: D( x
( t1 c: b: V9 ?# y. n
z- i2 \5 U# c4 y- 8 I3 r8 y; {1 p! c0 Z
- /// <summary>
( U: a n" ^, l( n& T - /// Handler1 的摘要说明
4 x, _8 b6 {7 S; U - /// </summary>) l' ^# w, k1 m0 @( T
- public class Handler1 : IHttpHandler
/ S: q U3 J3 M# Y$ W& n - {
1 n' H! Y' u ~/ u# @$ m: v - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池# b, g/ D, k! N4 T% P
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
1 R4 D( K4 m# b+ ?# Y& Y: ]- x - public void ProcessRequest(HttpContext context)+ H" J ~0 C" l( E
- {* j! J# p/ i, E" I8 e1 n$ q5 P) Y9 \! m
- //context.Response.ContentType = "text/plain";% X2 H3 d' D6 H. f1 Y: }" E
- //context.Response.Write("Hello World");
: V3 v* j( a4 d- M1 Y6 ]1 n8 J' U. N - if (context.IsWebSocketRequest)! z2 | @+ {" Q0 A2 [# b
- {' E; N& c& K0 ~7 n' e
- context.AcceptWebSocketRequest(ProcessChat);( N3 C' T% a$ C9 u2 h$ `0 T1 G5 m1 ]0 }
- } 5 j* }4 v* [" A
- }
) I& N: I3 v7 P$ ?5 k
* S1 j* ~: x: e5 o/ D- private async Task ProcessChat(AspNetWebSocketContext context)
6 m6 C$ `% N( c+ r; ~5 i6 H9 g - {$ F d, H5 I' r" g9 I% P
- WebSocket socket = context.WebSocket;7 ^/ j( m. Q* a! @; {
- string user = context.QueryString["user"].ToString(); L8 `7 r" }/ A' z# X, q5 K. n
$ S+ ~9 @. k+ [2 a- try9 n0 j2 t. R- |1 a5 T5 \8 g
- {) e( O2 K/ ^) S/ G# H3 g U! l
- #region 用户添加连接池
2 @0 |' i: t+ D' z1 c - //第一次open时,添加到连接池中
( j) Y( O. U/ v* B1 x - if (!CONNECT_POOL.ContainsKey(user))9 g: I+ f: @. a' ^0 O |/ O# R
- CONNECT_POOL.Add(user, socket);//不存在,添加
7 w( \, a. b- R# b - else3 y% y& q! j/ {2 i$ M3 s! U
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新2 x' Z6 L1 i& t3 V
- CONNECT_POOL[user] = socket;% [5 e- z1 z- l4 u& U4 H7 T
- #endregion9 ~/ o$ I* |. c$ v* ]
- - p& E, h3 k* U/ H; }+ ]6 L
- #region 离线消息处理6 m: y% n0 C6 J- V8 z! a, z3 W
- if (MESSAGE_POOL.ContainsKey(user))
- H2 U% m, d ~# I' P0 D - {( `( [2 ?$ [% Z1 R7 ?
- List<MessageInfo> msgs = MESSAGE_POOL[user];
( `* J( `, k3 j - foreach (MessageInfo item in msgs)
1 y5 C5 j; t" ~' w% a8 M/ l+ X y - {) \: z+ [1 z7 l7 A' t
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);& A# q& Q/ W# E1 J8 O
- }
2 D+ o( n; X: w, i - MESSAGE_POOL.Remove(user);//移除离线消息$ C- _0 V1 m0 H; o
- }7 J" k$ w8 \4 }, B. ?7 F
- #endregion
1 s+ }% Q" y7 o* l3 p6 t
2 o# F, g, U1 P& ~* n7 V$ K- string descUser = string.Empty;//目的用户9 O1 q! D F: Q1 y* S, a
- while (true)
3 X4 }* A8 v+ G5 I+ b - {
P; n' S8 j7 Q D8 p - if (socket.State == WebSocketState.Open)% h8 h% O6 q& \' q7 |
- {+ B3 L! y, [9 Y
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
. Y5 v& H1 e8 f! J4 P - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
% v# f+ Z6 P. t - / y$ U* N9 o0 g. f/ I, S
- #region 消息处理(字符截取、消息转发)
! C4 o0 F6 W/ ]/ @- b: r - try6 g8 T+ i) }8 D
- {
0 @0 c# Z% n6 [* u - #region 关闭Socket处理,删除连接池. o2 F2 ?6 L4 e( L' i
- if (socket.State != WebSocketState.Open)//连接关闭. H1 `' B0 c# M
- {
3 q+ y* ?3 R% r) I0 `" ~ - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
- j- j# D9 T8 p8 [6 B/ I - break;0 [+ \$ H. R7 E' J8 F: a6 ^6 y
- }
. J" ?& W/ |; ~$ e6 U% j: } - #endregion
% G. w- |; V, L- W% Z+ N
0 g( p4 N ?$ \, d0 S- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
% s d! y+ i5 c2 p) g; R5 J - string[] msgList = userMsg.Split('|');
* X& w4 h3 Y) t- ^* v4 I+ [ - if (msgList.Length == 2)
9 n8 `+ d) j' x. ] - {, \; L0 A) u; g+ D: j1 i H! C
- if (msgList[0].Trim().Length > 0)8 I" l p3 O- e
- descUser = msgList[0].Trim();//记录消息目的用户# R; n' t0 h1 e$ ~# [
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));& g$ _6 Q7 E A* y- ]0 U
- }
2 G3 Q X3 j, x, ?7 Y - else% T4 x7 u7 T b1 h8 j0 W% w1 L
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));- C" ~ W; w% U0 ]& E$ w1 f
- 0 u& m) Z$ n5 Y8 P7 h4 |& f& |
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
, l; U. ^# m, \) G h4 N - {
1 |/ W% k T% f8 N4 i y - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
: S/ r1 t. v, y3 y* C9 l" `, ? - if (destSocket != null && destSocket.State == WebSocketState.Open)$ D- O9 n5 u2 C/ \
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
: D9 c1 f$ D; T5 a8 E - }! N6 W4 Z/ E( l4 O8 a! J
- else# `! n" T- w, q/ I4 E- v4 J
- {
+ x$ O% M2 W2 Q, B% x3 X# u% z - Task.Run(() =>
v8 j9 X- n: e! g - {/ w( G; H& ?0 _2 W
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
) ~3 Z4 t: B$ C2 G' i6 @0 |* D- S - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());* H- P/ X: T+ H, t! g, o6 x% {* J
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
- g0 K2 g6 P* p$ c) l U: N5 W - });
2 f3 U- P, h$ V. i - }
* p: L% Z: R9 ?% ]. o' |4 l - }+ E9 n l1 Q, u0 X+ i
- catch (Exception exs)- Q6 |. k5 A/ P! J* g' b t" g+ O
- {
1 L- I$ X Y O# y2 x: N; }, ? - //消息转发异常处理,本次消息忽略 继续监听接下来的消息6 t, Q! _! S! g/ O- J
- }
+ A# M% |/ O: @6 ?) y! k - #endregion
i! \ @ Q7 E8 R8 ^" s* i - }7 I4 z! [. [8 L. }) Y3 {* o
- else
* X2 W; k8 B( T- y - {: O- w2 a& R, l. t f! r
- break;$ ^2 S c1 f, Z# L
- }
8 @, `% n8 E; n - }//while end
# R& D3 z+ U5 d# Y' K$ f- i0 o - }
& z2 F5 q: H$ I) ~1 ]/ ? - catch (Exception ex)
3 R8 y) i, f r - {
( M f3 N1 k' r% s' G/ a - //整体异常处理6 P$ _3 R+ w- c6 W! q+ u
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
* C" O1 ^' I( B$ O1 ~2 z - }
* N" c4 a. \# g0 Q, g - }. S. }9 S d$ Q5 R8 H
, V4 k8 X7 w. S7 S' m
3 c6 j% Y5 Z; j- public bool IsReusable
* s4 m9 g7 p: \1 u# k" _' Q6 M - {6 P5 k, p! U: Y3 m9 P0 z6 G
- get
. g0 y' o5 |6 O; h - {
. i V4 Z$ U6 i9 i& h6 F8 | - return false;
; u3 M0 k6 G: J! x; H - }
5 k" W9 ~% V7 F% p2 m' ^) X - }5 S% B) Y: C: k4 g: \4 E0 x5 t
- }
+ _" ?- {4 ?; ] - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 2 U9 v! S2 o2 v
|