|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 & A2 Y4 w5 G7 Z# O' }8 z# H7 k
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
- D3 l: A: A; d. e - using System.Collections.Generic;
0 b' `) @, D3 z7 V a - using System.Linq;7 X* \0 y& r( v3 I+ C# P3 [
- using System.Net.WebSockets;
% e$ ]! R( d- F5 _ - using System.Text;
8 T1 l: J; {' ?: W6 j) V - using System.Threading;
; a1 i4 x9 K* D8 N/ _$ M7 v - using System.Threading.Tasks;
- X0 g3 E5 x" ?" l - using System.Web;% P& [* Q8 R9 v2 u6 d
- using System.Web.WebSockets;+ V: x/ l2 z2 B/ d1 S
) ?6 r& ~ Y& I# l- " m# b3 f0 W. I, f3 @
- namespace WebApplicationWebsocketHandler6 p4 o# R9 p3 c- b+ R# w3 \
- {% w! P+ V) |2 [5 f9 `! c+ i
- /// <summary>9 Q/ n+ @/ G+ x' Y8 U
- /// 离线消息# [8 h8 p4 Y0 S6 e
- /// </summary>! J0 H3 c2 ]) s; @
- public class MessageInfo$ {+ I) k( O) {
- {
' T7 j3 G( r9 [. ? - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
3 R2 T# t, O$ e2 }) a; T/ d - {
# e& F+ g3 ~* i/ F9 r$ J8 g - MsgTime = _MsgTime;0 ~: q8 B; U* Z) t) C" X
- MsgContent = _MsgContent;
. O7 \$ }; q) `' v3 G- X ^, j - }; |! m \9 i j& e1 r
- public DateTime MsgTime { get; set; }
T- y; B; u4 k6 M* T N# Y2 G - public ArraySegment<byte> MsgContent { get; set; }
. |- \/ C0 O1 {- E* l - }2 G8 g5 v) u; M5 S7 s* v
$ ^. D/ Y) ~3 L1 v# h1 f
2 k. Q" J$ n/ h- % s" R; U4 `( G4 C) k$ Q% t: {. n
- . C2 [: C4 U+ O0 N- K
- /// <summary>
: A4 u: W- n4 G7 [# d6 f3 t - /// Handler1 的摘要说明
9 P) M0 ?9 U/ S - /// </summary>9 S" U. c$ r7 ~( j1 }
- public class Handler1 : IHttpHandler
1 @5 g; K. m+ p5 C7 d. f4 F - {
6 P+ `4 X! U( S- G U+ O4 l - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
! \3 ~. ]' m1 v9 ?, o( t" \ - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池! N- r( `# B0 p% K9 H5 B: s" @# E+ ?
- public void ProcessRequest(HttpContext context)( S% m. a+ s4 c3 |+ t
- {
, a4 i/ ]$ R }! y) P! G - //context.Response.ContentType = "text/plain";
5 d2 y; [: `+ o: ` - //context.Response.Write("Hello World");
% y: O4 K6 L9 ]/ A! U8 _3 M3 M g - if (context.IsWebSocketRequest)& l/ H3 C3 ^1 Z ?$ i, f# W( o
- {
7 b! q% H8 ~, \8 M" u - context.AcceptWebSocketRequest(ProcessChat);# X$ X3 B% n/ R
- } 8 |1 t8 ~5 I; U! L. p
- }
0 t; y- z- j l; c! G( _
8 o. e; N2 p. f+ c. e6 u- private async Task ProcessChat(AspNetWebSocketContext context)
, ?1 K+ h+ @ l+ C - {
' \3 Q$ D( A* H! G* ~ - WebSocket socket = context.WebSocket;
7 g; \- t7 H/ s9 P8 L - string user = context.QueryString["user"].ToString();6 e _/ W5 { R y& `9 }
* s6 y% x1 N& {9 @5 u) A- try3 E$ J4 G, [9 _9 C
- {
{" C$ G9 S& [. h - #region 用户添加连接池
2 r( \* F7 A! @& |3 b" C- Z - //第一次open时,添加到连接池中: v$ l8 f7 R9 U! H x8 o( G; N
- if (!CONNECT_POOL.ContainsKey(user))& Y6 p" ^! L3 G/ @# C
- CONNECT_POOL.Add(user, socket);//不存在,添加3 ]9 H4 ~ q) |9 u7 W! ^
- else
; {/ V/ S4 K* L6 l( a5 L, Y# R$ y3 J - if (socket != CONNECT_POOL[user])//当前对象不一致,更新8 y7 v% H E$ d: }, D: W( O
- CONNECT_POOL[user] = socket;
/ I" g) ?7 |5 A7 L# B. ]; l' R - #endregion: R$ ?& u- e" S3 c, Y3 I
- 5 s# q2 b0 C9 O% O
- #region 离线消息处理. a2 R) x1 `7 b a) _ d
- if (MESSAGE_POOL.ContainsKey(user))0 b: c( X7 c: b; C- ]
- {
( \- r7 g* x, @3 b - List<MessageInfo> msgs = MESSAGE_POOL[user];
, o( b6 B7 I o& d - foreach (MessageInfo item in msgs)
: R1 [+ O6 n# N7 `7 c2 ? - {6 l, V2 _, T( E$ d, h2 F$ @8 T8 J
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);- ], ]2 ~, Q1 F& ^
- }
5 C* f8 \% V( r - MESSAGE_POOL.Remove(user);//移除离线消息
: w1 u# o O+ \- @* g - }% w4 |# t# f1 R6 b+ J; Z+ U# r
- #endregion. C" X' D$ J. S p0 y
- 2 w* Y/ r: Z0 B7 S w
- string descUser = string.Empty;//目的用户
5 d% k5 U$ f; A" i3 U' ] - while (true)
# L6 m( M( R" C - {' Y8 A: h" y. Q' E- |' o
- if (socket.State == WebSocketState.Open)4 ~! \7 Z; }# j6 i
- {2 w7 W, O6 p! e9 _+ P& a
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);. o5 {" s9 K0 `) u$ b( \
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None); r' L% p3 l0 W! x+ ?/ z h+ f
3 ]7 s: K) y+ d- C" ?2 Q6 ]- l- #region 消息处理(字符截取、消息转发)
8 `5 Z, j$ w( Y - try: X4 A' Z- I+ n) p' V# F. P7 Q1 _( K/ y
- {$ E# `( I$ L( {$ Q, c7 s2 F( F
- #region 关闭Socket处理,删除连接池( U; u9 O/ A6 [
- if (socket.State != WebSocketState.Open)//连接关闭 v$ l% j: Z! z8 A
- {
5 p5 h3 i3 ?) {0 F# P% w+ h - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
0 ?' C) |) e; i% v1 r - break;
) ^) P5 r& B3 ^ Z - }
$ d1 T. `; [ Z) j - #endregion
+ Q: ~4 K; O2 ]1 q- K. l5 P - 8 e/ t$ F& `2 U# k" i" V' b* {* R
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息# L7 R0 Q( b5 C
- string[] msgList = userMsg.Split('|'); T4 G" M7 y- g
- if (msgList.Length == 2)
! [6 A @) p0 n- X - {+ A0 M! N g6 Y0 m; O& I5 y" @
- if (msgList[0].Trim().Length > 0)0 j F2 R1 C, c6 u) W6 G) f) P1 _5 G
- descUser = msgList[0].Trim();//记录消息目的用户1 B8 @+ v6 {0 J( V2 R
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));5 R% h! A. S+ E/ M& v
- }$ Q3 ]: _9 ^7 H/ Z7 g
- else
* r% g4 a+ L$ N7 y7 H1 Y - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));( L5 \+ g" v3 k7 }! y
- . n3 C) k5 S) f2 J
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线1 c4 ~4 X$ \( I1 `
- {8 r8 g$ r# m% [! H
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端' V2 E1 q" z* |) b$ P
- if (destSocket != null && destSocket.State == WebSocketState.Open)+ K3 p1 H% f1 }/ F3 F$ ~
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);/ w, Q2 x6 Z# O4 B) ]% h
- }2 Q: J3 P. T' j1 }3 V
- else* H. }9 ^2 m& Y; n
- {
( @+ f7 h' T! N( _3 J4 [# J& v - Task.Run(() =>* g) g4 ?, @2 y8 l- j7 y
- {
/ l; Q7 a- g5 Y( h/ r - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
" W0 B! T/ o" N0 v) K. j2 M) l0 j - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());% _7 v. E) R) ~0 s, c; p+ h
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
7 I) e3 ]- n: b/ E - });
( ?7 X0 {4 ~& ^/ I8 q& O4 y' x0 ] - }
' l2 j. |$ M) w; Z% s* R' m* g - }& _/ T0 g2 s, W
- catch (Exception exs)
" F' j( s$ H5 M. A' q' ~' y; c - {4 \: \& E4 J$ ]+ s
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息) j7 k& ~0 U1 O) V6 I/ T. A( ~* v: r: z$ k
- }
, p$ n" P5 C: L* |3 a0 ? - #endregion
' Q4 r1 I& K- W. J! Y - }# n* W" O t: w5 b0 ^
- else* j6 q1 {' d& i1 k+ y
- {7 M6 j* g% T& ?. i
- break;; S" Z- _$ i- X% r; N
- }
5 a( W2 f% k M7 k6 {' r& z% p" E - }//while end5 h2 h. d' z. h
- }3 q5 u# X2 t: V. O
- catch (Exception ex)
9 Z0 ` ?! A1 { l$ \6 i$ p - {
6 l; z- C2 U9 q! t2 H4 C - //整体异常处理5 i7 \/ W$ V$ U2 d( D5 j
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
6 C- O* g! j; e6 M* S - }% S, _6 f; @$ h- F; g! q
- }4 W$ g! T9 b y' N; F
& S8 c# N8 J* d" O! B+ X- o$ ?) i$ \" [% @
$ ^# d. m( e4 U$ ]. O- public bool IsReusable+ S5 F! O+ B$ C
- {
2 X0 y& [) a1 f/ w- o5 Q - get
! S/ Y9 u* ?- F3 Q% t9 o - {
3 g0 K2 E/ I$ n! Y, b( T - return false;( L( u' B1 S( X& x0 h& U( r
- }
6 ~( c: o* {; f5 o: H+ p+ ` - }3 _, o) ]' b5 d5 q0 W2 U- J' p
- }
/ w2 Z# Y" [6 G: d$ R! g- f2 i+ Q - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
[" ?! L: e |& Y" G |