服务器端代码编写 1.新建一个ASP.net Web MVC5项目
" V, }6 }1 f5 L% O2 z+ }2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
& F. J0 J1 n# f9 R0 Q - using System.Collections.Generic;' s& `" G ?/ g5 S: L2 [4 B
- using System.Linq;4 z8 f3 s3 {3 ]0 W( [
- using System.Net.WebSockets;" B! I) L# t* h! Q
- using System.Text;
/ M9 {; q1 X* r. p% H2 ]. | - using System.Threading;5 ?8 r6 u8 V( L3 v. W
- using System.Threading.Tasks;
9 p" x9 |1 P6 _; l7 D - using System.Web;4 {1 h: q! K# v
- using System.Web.WebSockets;
" b1 N: P# C7 J; Q - ! |9 ^2 F, A; h5 A+ ^
- 9 F% n. d$ f, \4 ?
- namespace WebApplicationWebsocketHandler1 n! ~1 T3 ` j
- {8 w( \ E- P2 Y. ^8 O6 ?
- /// <summary>/ r# F9 \, ?, Y# V9 I" M/ `
- /// 离线消息/ H0 x! a' g9 S( w: F
- /// </summary>
) R5 b& Q1 ~6 [) X, d' v - public class MessageInfo; ~: z' `* s9 i3 J" `
- {+ O4 z2 [4 I' e @0 O' Z- ^
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
+ R' k/ N) n7 K+ j$ V& Q" x - {1 F. p5 z @* W. o, J5 Z
- MsgTime = _MsgTime;
, {- _. U, }4 X0 K, F3 o - MsgContent = _MsgContent;
, R+ b! N- b G9 A0 N - }' e/ L( M5 f. a% A$ H' M( C
- public DateTime MsgTime { get; set; }
6 a. ?5 |" X/ X& P - public ArraySegment<byte> MsgContent { get; set; }. h; B) T2 z+ e( |
- }
8 _- M" M& r) j; @2 E" } - 6 E" D# T0 M# s' J! `
# ^$ x5 E! i! _, ]$ i- ! t8 d7 n; f; j8 _1 z7 c6 y9 a
- 3 B. a& }5 Q3 J& Q, ~ p3 t# k
- /// <summary>
3 t/ O, P$ U( l8 j - /// Handler1 的摘要说明' W! F2 \/ ~3 |, r6 L/ M
- /// </summary>* ?2 l( |; [. j$ M' ~: n% V2 x
- public class Handler1 : IHttpHandler) k: v& m" b: F4 b& W3 ^ f
- {
" I" {) a8 O s* a( v - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池8 U$ D/ e% Q. n5 i: u9 [
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池0 z( K# |7 O3 ?
- public void ProcessRequest(HttpContext context)$ ~" a) N3 _ \5 q5 J# _
- {8 A4 t1 ~8 s7 z6 ?6 M
- //context.Response.ContentType = "text/plain";$ e) f- Y7 g N& m4 m
- //context.Response.Write("Hello World");' G4 ?6 p$ K- I
- if (context.IsWebSocketRequest)) d. H- M% R6 a* L% {: A! p
- {
. Y. P: w& \5 R$ y9 f7 x% u2 ` - context.AcceptWebSocketRequest(ProcessChat);# q0 ]2 @2 D- H4 k* ^. h
- } 5 b+ M0 p6 k+ ~ J% E) i! Y, }
- }" ]9 _6 ?' n# q
! R7 Z4 K7 K) i* O+ T5 M' y! r2 u- private async Task ProcessChat(AspNetWebSocketContext context)$ w2 ?- ~6 \# u6 C
- {
0 v9 Y" {& v8 H& X" L- t - WebSocket socket = context.WebSocket;9 {* e# F) W( E( h& A4 \& a7 Z4 @9 Q
- string user = context.QueryString["user"].ToString();0 X& a- }* [7 P) a0 Z3 K
- ) r* k+ Z0 V9 x( c
- try; u9 Q& v9 G9 f4 M/ K
- {
9 b* U% N' O% b1 d - #region 用户添加连接池
" h& G2 k9 h; ^" _ - //第一次open时,添加到连接池中
# }$ C( |! a1 m9 j+ Q4 o - if (!CONNECT_POOL.ContainsKey(user))
4 G* W! A, I4 L+ C - CONNECT_POOL.Add(user, socket);//不存在,添加2 D# G3 R8 B2 Q+ N9 l( L7 i
- else/ G* m s7 c$ F
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新8 f8 k) c9 T, r, I" Q) N& F0 A
- CONNECT_POOL[user] = socket;
0 D) [1 u1 @$ s/ b - #endregion0 f+ H% l* g H0 Z1 t) t G
5 e: {- Z p4 f0 I. z1 b6 l! ^4 X- #region 离线消息处理 R% y8 e" u% t! H7 F" [- j2 k
- if (MESSAGE_POOL.ContainsKey(user))* d7 v* S/ o# F& v8 H- ^7 ~8 ?
- {
+ F# t/ X! N3 G$ f - List<MessageInfo> msgs = MESSAGE_POOL[user];3 v+ S- L" F5 @/ V
- foreach (MessageInfo item in msgs)
# J4 o6 M2 c- P - {
% a7 l2 Z3 Q3 t2 ]# i" s# ~ - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
8 Q* T/ x% F$ E* O! a - }
' f/ \1 w* X$ n# Z9 B* Q - MESSAGE_POOL.Remove(user);//移除离线消息/ p: r: }3 s6 Q" ` t
- } Y* i- @' _# n w1 |
- #endregion9 H' s( o6 ?2 m; }% C
$ R/ r$ {! N- [; `* B, _5 X- string descUser = string.Empty;//目的用户7 n5 \9 U: Q4 S8 ?/ Z, R! x; f5 f
- while (true)! W* J$ f: X! d6 A/ A8 H
- {
9 X3 q/ n& n7 }; ?' @6 x- T - if (socket.State == WebSocketState.Open); |' \" o6 v6 A; u. U, a2 ?" F/ L
- {4 [: E) W* l/ [ ^
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
0 b# k% m7 }) Q2 f( l$ }9 x. } - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
/ r i+ c4 T2 D4 w( X, W
0 T+ r, |& r. J) k5 Y, E- #region 消息处理(字符截取、消息转发)
) t2 p5 S* u z% J0 O$ {) J8 M - try
" Y# L6 L3 \, p' Q0 w2 ]5 y - {
- \1 p. ~" K: c6 d) u! @2 S* o - #region 关闭Socket处理,删除连接池; q+ s& {5 \7 z
- if (socket.State != WebSocketState.Open)//连接关闭
: m, u: Q4 [+ @$ B6 `0 u - {
; W) c3 g% k1 c5 m& F - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
! r0 r3 X& x- C/ E1 z - break;3 C% N4 z( l4 @
- }
% V N( z3 o V# b( ] - #endregion% N4 u+ w+ Q q
% J4 a, n+ E+ V: A+ x- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息! t! W1 ]' O2 }, Q
- string[] msgList = userMsg.Split('|');
: i7 a4 g6 m, d; E6 Q - if (msgList.Length == 2)
$ L2 P1 h! n( X( q - {0 d, Z0 w1 _3 S2 L- S3 D2 T
- if (msgList[0].Trim().Length > 0)4 q k2 A( X' [% N1 x
- descUser = msgList[0].Trim();//记录消息目的用户0 O! c- w9 ^, d- Y# @8 O7 u! }
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
$ \$ o! f! G7 V+ `3 r - }
' e+ d2 ~& q6 ?4 E - else
1 Z& Y4 r1 T( a( o - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg)); G p! @$ ]& H% b! y A
% x7 A4 E1 m; P7 B' d- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线7 K# K7 I' j2 H+ t. x+ i
- {
6 R* x3 M; o4 f6 M- j - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
, e, m' _2 E+ R - if (destSocket != null && destSocket.State == WebSocketState.Open)" Z' _$ W' D+ ?! a# c
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);9 X% B& T6 L, [9 U5 F9 h
- }% J7 w5 T) ?8 q$ i
- else
' L- u$ j/ O9 m$ t" ] - {/ r4 N( r3 x% U: O' o
- Task.Run(() =>
0 \ |8 b2 F4 o& [! S0 e( i - { T( {9 L. k7 ~" h
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
' I5 h$ _4 l s; |& s - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());8 ~! C* H8 Q7 _6 t
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
( u- s% n. H5 S" O/ @ - });" w1 b- Q' N" _* p1 j. i
- }4 W+ @ G3 s4 i. p# M1 d; Z
- }
. \/ c7 I! I9 H; I7 f# L+ d" e - catch (Exception exs)
! D5 e& u, [( C; c: s n# ] - {6 y) J. B: Y$ b/ H: d
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
7 f- ]# @; u, d, i5 N! k - }
. c# M& S" ?" f4 L - #endregion4 X" A$ W) W, t8 M/ N
- }
( V3 V/ F9 F- } - else3 r }9 @+ t* U6 I2 R
- {9 h" z4 O9 @, E% o! |
- break;
# o( ]; O( t7 j0 _: T( a y1 E. u - }( n( D; p6 d( l" E* f! J
- }//while end
! |/ H5 E% Y0 @, T/ E - }
& w* d3 c8 g X: g# m- x# F6 Q* R/ h - catch (Exception ex)
/ R9 d" J- p1 t1 T/ d a - {
0 L2 I" M7 d, v - //整体异常处理; a- R0 @6 X0 Y1 X# a; t
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
) g& L* D& G3 Q' A - }: h+ ^7 R/ d9 w+ B& J: {+ L
- }
) \( ~! E9 @5 d4 ^7 F( _$ c7 Q
4 g g0 r4 ]# b- 8 Z& u2 X7 T& Z# N' m$ C1 {3 C
- public bool IsReusable
6 z/ I: c3 F+ Y9 D - {2 d8 c' \% f. _ w" s: Q; ^ K- _
- get; e) r2 R! P# w( e; O
- {2 f5 d" u' d: K: y4 }( C
- return false;/ ~0 E6 Y# i1 Q' }
- }0 r3 t/ Y* M3 N/ H0 i' E4 m$ f$ p
- }
8 d" k( r: _0 [+ N4 b - }
( ?/ z/ K5 w' m! |5 u) S$ V - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 7 W+ n+ M* ~+ @- Q
|