服务器端代码编写 1.新建一个ASP.net Web MVC5项目 / p6 e$ S' `: ^
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;: j R+ }& W" j
- using System.Collections.Generic;1 Z/ C# L( N9 F2 ^% m) k' a( ]
- using System.Linq;
. w0 `9 ~ Y3 a - using System.Net.WebSockets;% |9 M9 r2 F3 N! m6 ?( d. G
- using System.Text;
+ m; H9 u1 K$ c! U" T6 y - using System.Threading;5 @/ X: R; b& h: k* ]# ~4 l
- using System.Threading.Tasks;
! W/ y7 K) A% o5 R2 A& c( i& {# k6 ^ - using System.Web;
) m0 X- ]2 ?$ d' ~0 E8 { - using System.Web.WebSockets;( Z8 h" l6 O0 w5 u
4 L" L- ]7 g! S- 5 f7 |) g2 u- Z3 i* h, D
- namespace WebApplicationWebsocketHandler
/ W x+ `" c0 W1 z - {" U7 a7 g7 x( D9 |! o9 _6 u8 g4 M$ U
- /// <summary>
h/ a! c6 b) w6 Y* g" o) j - /// 离线消息7 t' H$ _( j9 Y" x/ ^ c( V8 U
- /// </summary>- Y0 f( Z2 [/ M6 G# h
- public class MessageInfo
# z' M s1 e. E# f& P2 a* v- A `) z - {
v, R" U+ d0 |+ t% H - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)! Z$ U9 u- W$ B' v( ]/ `4 \: j* E
- {
s$ _9 |) [) V# Z9 H8 p$ R# l - MsgTime = _MsgTime;
" ]: `, T* }2 u- Q/ A; Z9 `. H - MsgContent = _MsgContent;% H. _ K& Q! o7 b! D" d: l
- }
) E9 E D* n6 k0 S i( N - public DateTime MsgTime { get; set; }5 o1 _" g7 m, e; A k' v
- public ArraySegment<byte> MsgContent { get; set; }9 n" Y0 k9 H: N8 k
- }
6 T. w5 j2 Q C6 l, u
Q: m9 P. e; j1 x' q- 2 p2 U: X+ H) b- H
- $ T/ }# d3 ^2 J, c
" [ p2 y& q5 Q- _3 o4 n. r- /// <summary>
& \8 X+ A- n' H% K$ S. ^ - /// Handler1 的摘要说明
" A3 h7 Q- A5 x, P. q' C9 ? - /// </summary>
1 u5 v9 A0 ^: S: V6 Y$ y& X - public class Handler1 : IHttpHandler
( v1 o2 \) b9 ^0 E, |6 D4 ~; ` - {
3 b: e7 i. z% l) F- U! C - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
# k5 h) ?3 _& B - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池1 K8 e6 G5 m) L1 g, E/ d! ?
- public void ProcessRequest(HttpContext context)* ~5 t. o0 ~- r# f% m
- {, ^, W9 x8 y( k6 g; Y1 v" z. x7 T
- //context.Response.ContentType = "text/plain";2 c( v0 ~' ^; S' m$ W. O! c
- //context.Response.Write("Hello World");
" \1 D+ {/ R' z, I, d; @5 v - if (context.IsWebSocketRequest)
, ?: m: h* D& O y/ C - {
# G( C7 u- P' H( d' S4 C - context.AcceptWebSocketRequest(ProcessChat);6 Z- `- y' t" h9 J2 }( x
- }
3 W, T. k6 y e- V3 V; _; G: g - }3 h2 y" \ ^" F/ j) d
. X- Z! ~# r/ w7 [' G5 m- private async Task ProcessChat(AspNetWebSocketContext context)* }& X9 h: b6 y% q9 K
- {; ~5 W1 D9 |9 G( Y) K! x5 u# S* O$ v
- WebSocket socket = context.WebSocket;
$ b# Q/ w& u9 G* z - string user = context.QueryString["user"].ToString();
, F2 d' E/ X6 o7 \6 X
7 u! u" O! \# `- try
. j V6 J2 y: r z - {
) d2 f' Q8 g+ A# W6 D# @ - #region 用户添加连接池% q+ s' z: O* t, S# C
- //第一次open时,添加到连接池中
# H3 }, [8 w" J/ N. K$ G: l - if (!CONNECT_POOL.ContainsKey(user))0 j Q: q* h: c; J8 G: h0 q u; l
- CONNECT_POOL.Add(user, socket);//不存在,添加
# J6 _+ \& |. }2 m - else, G0 K! B M3 d: ^# M% X, c' }
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新, N, j2 V B- E {. `
- CONNECT_POOL[user] = socket;
O) V5 U9 z1 r) L" A: @ - #endregion
. w/ Y1 Q7 x& P- e
r! W1 U2 E: L4 Q! ]0 I" d- #region 离线消息处理$ v; Z7 J/ A7 ^! d5 Y
- if (MESSAGE_POOL.ContainsKey(user)), P4 {8 q/ h8 v" [
- {, q7 h( [, t$ B w
- List<MessageInfo> msgs = MESSAGE_POOL[user];
( R% V+ h/ X2 x0 J3 r' b - foreach (MessageInfo item in msgs)
0 n# _- X; [$ ] - {
) r; r! s, W( L {+ F1 N+ I' ? - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
" h0 \6 l/ b9 R; D4 s0 t- ]0 _ - }
7 A s& i4 g; q0 O; h# s" m- \ - MESSAGE_POOL.Remove(user);//移除离线消息, o3 M% ~5 N5 N
- }5 [) Z4 i8 D& v$ ^
- #endregion6 X( P3 M1 D# Y9 D6 P
3 |5 a/ ?2 n) @ |* N# p- string descUser = string.Empty;//目的用户) s6 N+ \- a$ b8 c, J
- while (true). q9 o0 f6 q7 D& x3 T; g# a
- {0 d7 B4 l/ C9 e6 e1 a& K
- if (socket.State == WebSocketState.Open)
7 B0 B: f% [, d0 T3 X - {7 P: o0 g3 E2 W) V0 [- R
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);/ w7 k1 G) q* @5 }+ M/ o0 E
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);9 z9 Y, ^5 f7 R
- : p# p i- ?: b M6 ?+ H, h( \
- #region 消息处理(字符截取、消息转发)
/ ~7 e- z8 q' L( ~+ j) X2 F - try; a* g+ C2 B/ ]$ C" Y% p! Y: `
- {" L% Y- }" U- c9 P7 y/ X6 J
- #region 关闭Socket处理,删除连接池8 {8 T( T! o3 q l
- if (socket.State != WebSocketState.Open)//连接关闭0 x( X4 q4 q* j2 l3 }: t |7 q
- {
0 G7 @3 P& E3 w& H' m - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池3 Y1 N+ t. n% f3 l6 x" ?
- break;
' R$ t- N V8 M5 k5 ~9 q H - }: d9 g5 c* g2 X
- #endregion
% x# q- a8 y( ^( p. O - $ S4 z4 E& w1 [" X7 f$ r' Q1 Z
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息- j3 P, |& e6 ?: r; ^
- string[] msgList = userMsg.Split('|');
% k! M' I' h: c - if (msgList.Length == 2)
! v6 N: y+ M u& S D - {
! q' ?. J h8 i5 s - if (msgList[0].Trim().Length > 0)! z3 r+ L+ t/ P6 M; }- x- ~' ~2 n$ G
- descUser = msgList[0].Trim();//记录消息目的用户
# C4 p& ?; L) o. B# P - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
$ w3 W5 Z! T- J6 f- q( Q - }% }: U1 I' Q1 G$ J, C3 \( ~/ E
- else# W4 q+ ]9 Y f/ ^4 Q' M
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
5 i# e7 s( q6 J7 `0 N* h8 I
: W! ^( \6 J2 |" |; Q, \- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线1 \ p! W* |5 B9 Q; s4 W2 V
- {* v1 i- l; T% [$ ]' l: _8 h" i
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
+ L0 ~5 d0 g; V" r3 O - if (destSocket != null && destSocket.State == WebSocketState.Open) K+ }4 N, O) d
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);1 f+ D* q7 z& x( a" T( e% y$ i7 @
- }
9 Q; g1 W5 B2 p+ k; C - else3 n# c: n2 F" m n, F/ s5 ^) C7 m
- {+ V, K5 g8 }( f D) s' s0 l
- Task.Run(() =>3 J$ _: Z6 w: t# w
- {; K3 D5 x0 _/ C1 L' H) {8 N( k. L3 L; v
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
& i. I7 K, n/ @; x1 S2 V! [ - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());% r3 I1 V1 D8 r, O
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息/ F8 ?, t# f% X5 F7 B
- });$ E5 J7 S2 J* L; g: B! P
- }' I/ W$ m C! |8 P
- }
7 d4 C( e' O% W - catch (Exception exs)/ H \2 b$ B% q0 A. H
- {! x$ p) g7 ?5 Q. z2 Z6 c
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
- _8 k( j- u# g' Y4 \# {$ | - }0 u& U: q7 q9 P* N
- #endregion$ r0 c: O, _, t) M
- }
( f f8 j5 k9 W! x' P - else
# x* p Q- i H- e8 w2 `$ Q) f - {
, `! U7 G5 a: b8 D$ B$ V' a - break;
4 {9 C$ K# J S' N - }; e: a% Z3 t, ?" @6 H2 d# u
- }//while end
+ C& `% \' O6 E; J! V6 y. z9 j$ X6 j - }
1 d# b' P6 z% {1 T. }; k* j - catch (Exception ex)
" [- @, l2 t" r - {/ A7 Y0 j$ C$ V7 i. d/ g
- //整体异常处理( ~/ S1 \/ G+ n" u) k" X4 K! I0 }
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
. c% \2 W; Q/ q9 ]! _- ~# D# v - }" F0 t$ z+ k9 Y% @" v
- }' H4 G- e* ^! t9 x* P# |
9 w' k* y8 K" e' u
. K$ T6 s D4 `$ y- public bool IsReusable8 t ]( S7 ?0 Z$ K$ s* q6 c5 D! Q
- {
( P/ ^' a2 y& a6 x' M+ C4 n - get
9 j* M, S) @% b5 O) }. ^ - {
0 Q" H0 [8 S7 ~( m8 X2 Y' ^ - return false;
. T5 p0 D, o' v5 p7 S: z - } j, s3 j: P# W" J# @
- }
' O) j0 N/ m7 _- | r! c1 J - }; D% z1 s' N& J4 a
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
% T) o, R3 P% ] P& x |