服务器端代码编写 1.新建一个ASP.net Web MVC5项目
; N. o3 q! x1 B/ `, g2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;6 Q5 Q) }- i5 C3 A1 x, q' [' ?
- using System.Collections.Generic;4 u4 D$ x9 T t* l
- using System.Linq;
7 v. z! y- T+ {9 @- {2 u - using System.Net.WebSockets;
# v% j; I: Q5 e! E' L2 C - using System.Text;
* ?9 B& G5 I+ j3 I6 a" E4 s - using System.Threading;
' W( H/ N# z# s. M7 V- @# Z - using System.Threading.Tasks;" G+ f; Z9 a" N% H: Z
- using System.Web;3 M. |% \0 k4 |9 s w$ a
- using System.Web.WebSockets;# o7 Q! l- ~+ n
5 |6 s/ X }4 f- y U- , `' w: v) I' H7 H! T
- namespace WebApplicationWebsocketHandler$ I8 A1 Z) S* e! p
- {
& G+ s- K: H7 m+ m3 v) m - /// <summary>
; x8 x8 F: x' l) Y* N - /// 离线消息
1 t5 ]) w3 L( H8 Z2 |9 E - /// </summary>
) x# `; t- X# Q - public class MessageInfo; E% E4 ]. x1 v
- {. n2 ^1 E& \, N
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)6 I% z6 x" D% B# |- N/ R
- {7 E/ _( k5 |0 ]- f. [" k
- MsgTime = _MsgTime;
* g% X0 F1 C+ o4 v1 w. I" w - MsgContent = _MsgContent;7 S6 g8 y- P- \) y
- }
6 Z) x$ d4 I! e, { - public DateTime MsgTime { get; set; }
/ D2 m" O& v' @* D - public ArraySegment<byte> MsgContent { get; set; }
0 h$ b0 C- A! m4 `2 C - }9 Z; k( c# y Z f
- 4 c0 g: N; L" |3 I9 u% z
- . h( ?: }% I8 Q6 q5 U- B! \
4 X6 q4 n+ f) a6 N7 d4 Q1 V
7 H% H$ o5 b. E! }- /// <summary>7 g" t- s$ v9 Y6 T, F" N
- /// Handler1 的摘要说明$ w5 C2 L' T9 z
- /// </summary>
3 \; g- P8 X, Q. x6 ] - public class Handler1 : IHttpHandler7 G9 u: y/ K& }0 P
- {
' q7 F* Y5 }2 F- a+ l d9 ~* t7 G - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
4 F# }! a0 a4 I. b/ ^3 B5 N+ E1 v - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池/ F) \5 l7 s- v/ M! J
- public void ProcessRequest(HttpContext context), a, y T: r4 a: ^* k
- {' |5 M& m+ _, k+ c3 e. O8 [
- //context.Response.ContentType = "text/plain";. U4 _: D: @' `0 v
- //context.Response.Write("Hello World");- {. s9 \- ~* Z9 b3 d7 t) @
- if (context.IsWebSocketRequest)
6 L8 J) ]1 O- i5 ?- u7 Y& I+ Z - {
0 B9 x2 C# A8 V7 I# K" J - context.AcceptWebSocketRequest(ProcessChat);
* `$ v; A% F3 i8 E* l - }
! Q$ |' {$ p1 ^ - }! m1 A& S' W j0 L P! Y9 G
+ t; D, k% I1 Z- x' k* @- private async Task ProcessChat(AspNetWebSocketContext context)
3 A1 p. }7 }5 d' ? - {
8 t2 |$ a# ^/ Z0 v* f3 ` - WebSocket socket = context.WebSocket;5 |8 a! D" _! }1 b
- string user = context.QueryString["user"].ToString();
; n6 F" F! b) ~2 S& M - # v, \+ d3 x, S6 b7 }& T' u4 J$ ?* }
- try
/ A' S! X; J/ P7 W# | - {6 s7 Z( t) e$ \% ]! j: f* h
- #region 用户添加连接池
1 W0 p; ], N% M N0 d$ y - //第一次open时,添加到连接池中
W* ?: q- Z$ N% H/ D7 r% v - if (!CONNECT_POOL.ContainsKey(user))" ]+ D* W: ?: R, k5 c0 ]
- CONNECT_POOL.Add(user, socket);//不存在,添加, J: ^3 T; P- K3 r$ c' I
- else
; }5 b5 `- o# z! _% p7 {1 i: j - if (socket != CONNECT_POOL[user])//当前对象不一致,更新; u4 Y; `# u0 R1 L+ f
- CONNECT_POOL[user] = socket;3 W W8 l- p. T4 w
- #endregion- n- \/ I( w9 M3 t: z8 D2 ?
6 r% `8 p! v( [% ]6 m- [ r- #region 离线消息处理: T# G# [* c* y2 y# I7 A, R# O- q. D7 j
- if (MESSAGE_POOL.ContainsKey(user))' m2 S+ r+ e3 |" _
- {
9 a2 w8 O2 J& u - List<MessageInfo> msgs = MESSAGE_POOL[user];& p' a+ m9 J& K3 r
- foreach (MessageInfo item in msgs)
1 ]$ x' n& k# L9 C4 H& ]6 [ - {
; m) _! o/ Y( h5 q8 ]7 M" Y/ u - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
$ m0 U, Y! z& J4 z% u4 D+ R - }
; M) ?, o' v# {5 c" k0 b# }, Q( B - MESSAGE_POOL.Remove(user);//移除离线消息 W% z, V2 h+ N. R* C- |/ D. Q
- }3 y6 e$ H( i/ c$ `
- #endregion4 `; o) l3 @- f' b8 g0 g3 X
; J- v6 @6 \) L7 {- string descUser = string.Empty;//目的用户
" x; s* G, ^: e( @) J - while (true)
8 k- E; p, E+ M9 K - {
# h- a) O# u: ?, _4 ^ - if (socket.State == WebSocketState.Open): X" D. z }6 A$ ?0 p
- {
i+ |4 W$ O( L" _ - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
0 N" L4 D5 L: f2 P. \0 }1 _ - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
$ U/ x( c+ w( R- @ - ( f# K8 b4 O6 A
- #region 消息处理(字符截取、消息转发)! w; Z6 @5 b! q9 f$ J# x
- try
* k! h& Y; p/ b' ]. T$ C - {/ d4 \5 }* @$ d0 @% y
- #region 关闭Socket处理,删除连接池* l0 V& V3 Y( s! I- Z0 W( p
- if (socket.State != WebSocketState.Open)//连接关闭
U+ L! _" L& F/ a+ b - {
) c1 {" ^3 c3 u) u3 I4 Q - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池' R5 J9 p" _. p4 g$ Y! D1 O: v7 U
- break;
( C( m+ |+ r. i% M+ ^ - }
" `* y: K+ w4 J3 V* m) e" D - #endregion5 q' |# H3 e4 r: j8 Q7 P+ _
( v+ F1 T) n/ Q O* t7 H- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息; p0 `8 i& p& u
- string[] msgList = userMsg.Split('|');
+ G v* z9 M4 R, @0 o9 g' o$ L! |. p - if (msgList.Length == 2): P9 S8 r* f% x9 K* P
- {, M) {2 f" A6 e$ q
- if (msgList[0].Trim().Length > 0)
) k; p* k; w. w6 M6 M0 a" w - descUser = msgList[0].Trim();//记录消息目的用户% N3 t1 m8 E6 [
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));1 Z% z' A d8 L8 R
- }
1 x. E1 [2 R5 l! Q - else' {' a* f0 R- l1 o. }. c6 x
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
1 `1 U2 L( V' u( m/ U( } \ - , X# T! Z a$ ?
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
5 }/ B0 W$ _, E1 m! h* Z - {
& L% K! C0 N+ P0 v3 d5 p% O - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
' b0 x* Q M: T# }3 S - if (destSocket != null && destSocket.State == WebSocketState.Open)
$ i( d( @: D/ `2 g* Q - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
9 ?3 Q" J- q" O |% V - }
$ }+ ]8 {5 F+ J! B: M - else
/ _; `2 e1 }% ?. n4 e# }4 m" Z - {
j/ `" n& m& [+ Y# k - Task.Run(() =>
! m8 K( y& e4 f, M( s' F, q5 k - {, }* v4 P) z. a
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中, B; l7 `0 ^; _# `
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
J1 v% G2 x0 W/ x3 h! o0 V - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
) U, T: v0 E5 Q$ o$ Y - });7 z6 z+ L4 `5 L
- }
- I, U* r. M* {4 F6 C2 m - }
+ h2 n, \) l! n* A: C y6 L( g - catch (Exception exs)2 y# x; p S l+ `1 `/ b# T% j
- {: t1 N" j$ k8 q% g, m7 K5 K
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息4 }; r: e% h# A8 d& M7 I* G" v- X% f
- }- U8 f9 Q( w5 G2 {2 z: s. i
- #endregion
% O, C- O. w# o% }2 A% q* d - }: T; u5 }, P$ I4 u$ @+ L7 W
- else
1 S' P$ ~/ L* P& o [) V - {: x& f* I; e1 S0 Q3 ~% o- l& W* e
- break;
; X; J! B" l- m5 S" k$ u b, ` - }* j% G! D) W m
- }//while end; ^& X2 l }9 q4 D) g8 j( e# t) v
- }: a+ ?+ [. X, a# @
- catch (Exception ex)) p+ L& {/ D' F) E8 a9 x. _
- {# r5 C2 u6 |9 `- k- k/ i
- //整体异常处理
; f+ U, U, f( T5 ?5 K - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);. I" d+ L% V3 |; i' K
- }
( ~& Z3 V& R& ]8 l5 G - }
. @3 B+ q6 y% L, `" X - / w8 b2 b$ N4 [! X1 [0 V# F$ T
* \3 @5 c. i2 \- public bool IsReusable* Q- G% U* R2 `: J, ^; i) Z' ]8 `+ Q/ c
- {
2 s: B) W" @5 ? - get
( n9 ^1 j$ t! j) c - {
6 W% S# J8 m$ d0 Y - return false;$ e% R; `8 h& n$ d: U% U6 Q
- }
! q0 W$ D, a; ?3 y! y/ ^0 G - }* j; g) ?- `9 J) m( m3 r( W' n
- }1 F) x; C) X9 c
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
* o, l; g9 ]# J% n6 C+ p% n! i |