服务器端代码编写 1.新建一个ASP.net Web MVC5项目
; ?. q. j" ]$ s. y2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;( Z0 e! G! {- {- ` D
- using System.Collections.Generic;
: `, n" d; n# y! ?) U4 G" i - using System.Linq;
4 K, Q: `$ v$ @* v [4 | - using System.Net.WebSockets;9 \& c# d" V1 R% p* Q8 {6 F
- using System.Text;
- Z6 d* f; x! K' Q# I: D - using System.Threading;
9 K1 n& L6 ]3 b* t C# {8 f# A - using System.Threading.Tasks;
: K; V$ [9 _! |6 t: `$ Z - using System.Web;
, o5 e- e5 a9 r$ S" b$ W, F - using System.Web.WebSockets;
+ {! j2 i$ G, |2 o- W5 g3 z7 [: N' O5 i - + X$ X1 s) P( x. W) m9 F
# x& r1 P1 W! y+ N1 M a- namespace WebApplicationWebsocketHandler+ [8 C7 s, C% ~) H& r: K
- {
* i# _" ~$ r; Z1 v) w, U - /// <summary>
$ S. A/ B! H' U, |8 V/ N - /// 离线消息
7 S- C0 G2 M" k* m- s - /// </summary>3 q! ^ k8 o& F6 Q1 I9 M: K" z/ u
- public class MessageInfo
' q1 z- C- J$ }) o# u - {
$ q# U- }: B' p' M7 ^- _ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
; \. R, h. z& ]% ^ - {
& r# O5 i% L7 o1 h, o: G - MsgTime = _MsgTime;
( F) o: h: M) i# \$ z, c0 r/ c - MsgContent = _MsgContent;
+ k& b5 ]/ N0 u" u - }4 p; S" _2 q: \# R" W
- public DateTime MsgTime { get; set; }
' J' T) l7 h: L7 T - public ArraySegment<byte> MsgContent { get; set; }3 z! F Q1 ]6 w _/ B
- }
7 ]) ~2 C/ a' K, P - " o; P3 `7 e" R" N
- % w! }2 ] p$ k1 [( O. d
6 T9 s6 K- y. {- ?" O, ?6 a# R% c
?6 F- y" F7 ~1 U5 I" h, y- /// <summary>1 d8 K. n4 M2 \% Y) D9 j5 q
- /// Handler1 的摘要说明
* @9 R. O6 ~, N/ M$ d - /// </summary>
% B/ \2 B" z$ q0 j! O" Z - public class Handler1 : IHttpHandler( Y, V. g1 w7 ]) X$ d
- {+ y. W, q( N6 r, ~" z q Q
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
1 o) b( |* U" T$ E+ f - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
$ Q- B2 ]6 f7 q- J- n" H - public void ProcessRequest(HttpContext context)
+ I4 k. O, Z* W! _ - {
) r% p% ^, s) ^9 }4 ~% E - //context.Response.ContentType = "text/plain";
' [* a! q$ h0 J+ J8 U2 a - //context.Response.Write("Hello World");
_! Q ~- i- P- U2 l. k - if (context.IsWebSocketRequest)
% i! N* {4 W! s5 s5 h: D5 x - {. B, t& C# s3 T1 O H2 m: H
- context.AcceptWebSocketRequest(ProcessChat);: s: a3 V9 ^" E% K
- }
( B& F$ s* \. }; U/ ]) s: J9 x$ r - }
: @: `& {7 Y1 p' v% I/ p$ T - ' w2 e G# h" B/ D* h4 p2 F; B
- private async Task ProcessChat(AspNetWebSocketContext context)
2 |: T% \7 K3 T s - {
" u5 J9 S3 {# L1 t) y; a, k - WebSocket socket = context.WebSocket;
/ o8 k0 z. _4 d1 p% v4 I4 b! A - string user = context.QueryString["user"].ToString();
* u1 b5 B+ c4 S2 _
7 y( W2 u( L; t) u, G+ M4 M+ F- try+ j9 U# m/ g& [# F
- {" y3 T+ E; U6 B9 t7 _( N9 r6 J2 V
- #region 用户添加连接池
) }. V. y* n& ~ - //第一次open时,添加到连接池中5 A4 `9 A0 i/ e. ^2 o3 H [) J
- if (!CONNECT_POOL.ContainsKey(user))% T/ z* z3 `" I. p
- CONNECT_POOL.Add(user, socket);//不存在,添加. `, |1 E) l7 U( T- ^9 i" t! x$ y3 {
- else- Q$ R. ~" c/ ^0 H' ?2 c
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
. v: [, x7 X' r4 B. R2 | F1 y, H - CONNECT_POOL[user] = socket;
. w( B. `4 D5 O5 F9 v% v7 E% r: n6 { - #endregion
+ D$ ^& C0 U" Z& i" g/ q - $ ~3 r5 C8 C3 A1 k/ T
- #region 离线消息处理
: `# X. W8 l/ k8 U3 ~8 [ - if (MESSAGE_POOL.ContainsKey(user))6 Y7 K: @) H, c0 K8 D
- {
; L" l O2 y) F1 C/ ? - List<MessageInfo> msgs = MESSAGE_POOL[user];2 A M5 b" S; H, D/ g7 M
- foreach (MessageInfo item in msgs)
+ j& Z7 k6 v7 o* a; B7 q5 E - {$ T: y2 Y) {; W3 c- Q
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);# w: L% X7 l6 W9 \- c" ^
- }7 a0 L1 t" O7 _5 ^' Z8 V
- MESSAGE_POOL.Remove(user);//移除离线消息
% H9 @ o: S# t0 o& c - }, [4 E- K: `, [5 n) y4 l
- #endregion1 {( I5 Z# c J) T3 r. U
0 F0 b& a4 X* |. S6 P' [- string descUser = string.Empty;//目的用户 \8 ?9 w) l2 ^2 j: U& X2 T
- while (true)
' _: D f) l; m - {
6 {3 @$ e. D9 e4 H' N" Q2 r S' k - if (socket.State == WebSocketState.Open)4 i! o' T7 {0 j' B8 U' \! m
- {% D" q ~! c) a! o
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
' K3 J" e2 U$ `9 G3 Q - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);2 k0 }5 ?$ f5 G/ Z* s
4 J% b9 x9 n. }: ~- #region 消息处理(字符截取、消息转发)1 W; b$ W- f7 Q: a( g3 O+ j, w
- try
0 X9 C+ a8 D3 g" R - {
P# r1 M& y2 @- B. @# s - #region 关闭Socket处理,删除连接池/ |* U+ Z/ J1 f1 A# Y
- if (socket.State != WebSocketState.Open)//连接关闭7 ?- m+ n( f& w
- {
( @7 M$ c$ M0 Y - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池+ t* j/ v' L* q# w# ~
- break;8 p7 `3 h1 O) ?
- }( w2 Z; ~ e/ w
- #endregion
7 D4 v+ v+ n5 g8 F0 Y - " L2 F/ s {. |3 B/ g
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
. C, S0 z7 o6 H7 `, \( d# N, R - string[] msgList = userMsg.Split('|');
: e+ ~" T9 r# A5 t - if (msgList.Length == 2)7 n( ?6 Q- F; F, A" c: g j7 K/ M
- {
. N$ C, l6 C) T0 R+ C5 _) ]% a: i$ ^8 z - if (msgList[0].Trim().Length > 0)
5 e4 d( K' Y5 [( ?/ O0 |0 @ - descUser = msgList[0].Trim();//记录消息目的用户
5 B9 x4 X: {8 x/ i& { - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));% R% c; E9 `5 g0 \: w9 O
- }
& {$ S7 H* `% y" n: d) m - else" @( |0 _# P p" m5 c" I1 I
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
' H9 W* M- R/ t7 {( u - & M8 j0 j# D' n- E( v
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线6 Y) f0 V+ q L3 p2 U$ i/ D# U/ L
- {
3 r* f; t- U: t4 T/ U: H. M - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端9 g/ _/ s: [# F- O
- if (destSocket != null && destSocket.State == WebSocketState.Open)
& d9 r0 z" @7 s3 @. K - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
' z9 s+ M3 l* Z: E" \1 A& m& ~2 @0 Z - }
6 \7 M# f+ v5 `, M - else
/ p) J7 D( J( V% Y" K - {+ k0 b2 r2 W* e$ r
- Task.Run(() =>
( l: `/ k" l- i$ l' m8 W6 f# A. ? - {3 c1 ?8 P; h6 |! i7 ?3 M* B: F. }" c
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中3 c; J0 m' P* Z& w( D2 \
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
8 F! m7 r- M0 @# W& \- s - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
- G [% ^5 `, U4 [! Q' ^$ ~: \ - });& [$ K, u: ]* v6 r; p# k% v
- }
, U9 [$ N! v9 K! ^* w d! b - }1 c- N! y! v% F5 | R0 {
- catch (Exception exs) w5 h+ c0 b1 e4 u
- {8 T7 a1 r% W( F; q
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
7 s& f( f& c, i, \, X6 Y5 b - }+ i+ d0 z' l- c( ^ p
- #endregion1 y; p- Z, Y' m E: m$ P6 {
- }+ U& j1 ]2 d4 ]6 z& D. U) T
- else: ?( N: J5 W# Q' B4 i
- {
2 \% _% H4 M: }! n" k - break;
/ O; c! Q6 a: [1 P4 t' { - }& z2 g7 A( |2 j, _9 b2 _, z' @, s* i4 w
- }//while end
5 S5 m( ~9 ^0 y8 M: k* K* B - }
: `! v+ ?; B) ^- ~; R - catch (Exception ex)
: [9 P7 \" I% v4 q - { P- ?% S/ i: ~- P. N( L2 F1 m
- //整体异常处理
# `4 a& ?+ g" y/ Z - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
9 m8 Z6 i8 q' e: r$ Q5 a# K - }
& ~! A# g5 K. x0 W; o5 ? - }/ b7 v; Z) C% Y
- 5 M' h. O1 T$ l. {
- ! c' V9 g; f4 D0 R+ W7 `5 U( r2 {
- public bool IsReusable
* d" O- f' A! ]! ?! O1 \ - {
2 t9 G9 u7 G9 E3 |0 v- t! i, X! k - get
8 g. X& `: G+ e" e0 ~% \ - {4 K5 A: C; y: D- L
- return false;/ Y' b7 J5 [& y
- }0 q( j6 N6 n, F; N8 I7 l7 r
- }
2 U, g& L$ j+ `( R - }
/ L) C, m* F) p0 b5 ]1 G+ q& N - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
" v7 Q" b& v( b) _) U: _& l, x) l |