服务器端代码编写 1.新建一个ASP.net Web MVC5项目 . y1 g9 S" b( N" S0 T3 s
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;& U3 A ^: ]$ Z$ X# q3 J$ H
- using System.Collections.Generic;' ^2 k) p- U; }4 e, ]8 \! u
- using System.Linq;
~3 _$ X. J" g% R$ Y7 p - using System.Net.WebSockets;
/ y6 Q2 ~+ d: z/ y - using System.Text;
1 M, l/ O: F1 w5 v1 @! e - using System.Threading;7 O3 U- S+ } r! V( x4 G
- using System.Threading.Tasks;2 A' L( N1 C% ~$ Y) _
- using System.Web;8 Q* I7 Q6 M" v+ h8 c
- using System.Web.WebSockets;
; d3 T8 K" {$ C3 V' l8 T
0 Q2 S: o5 K" }9 {' _; A
! b: @7 \, z, f) D3 j, M8 T# _- namespace WebApplicationWebsocketHandler
2 u: m: p, |+ u - {
8 _: ?& d D8 I3 P8 h0 d3 D - /// <summary>
J7 ^ Z% _6 F+ p& } - /// 离线消息
7 m" M+ Z o" Q- R - /// </summary>; H1 |1 t: ~- V0 e1 V
- public class MessageInfo
8 b5 j; j& @2 ? - {
) ^4 {, D" c% h ]7 ] - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
3 k6 `( [+ c. K" F - {
! V: Q3 v" _, A" c - MsgTime = _MsgTime;. T ^8 G- C, |: m2 S1 q# l+ w) N! w
- MsgContent = _MsgContent;& u, S2 H) L& R! U6 U& O
- }" M* m& y9 R& x0 J* @6 Y Z9 u7 h
- public DateTime MsgTime { get; set; }
- f; r& g! Q# W, q - public ArraySegment<byte> MsgContent { get; set; }
! [5 V5 X4 W' ? - }0 ?: ~' m1 t j* Z
- ' i6 _( _0 R2 F6 B" `; q& ~
- ) g2 C" m5 j4 E) z0 r* t2 ^* N) F
3 z: G7 }" F* c. q4 t4 c% }
. Q% \, A5 T( L; ~1 n- /// <summary>8 }5 z# m' A/ m% K
- /// Handler1 的摘要说明
# L: K4 G" w) z - /// </summary>
' I% N3 ?4 \ A% x3 ~$ A; m - public class Handler1 : IHttpHandler# C$ j1 N& c! V
- {( i3 p" P. v! q0 r% q5 {' a# @9 B K
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池# a. V6 _1 d* J7 o
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
1 o# H5 ^; `, s* F0 A - public void ProcessRequest(HttpContext context)
2 p4 u& I5 @: |# L3 b6 G0 j4 a% D - {2 D& b! E) q8 A# t8 K1 R
- //context.Response.ContentType = "text/plain";: W; z% u b& s8 Z- V
- //context.Response.Write("Hello World");, k: P. _* R5 Y, l- U
- if (context.IsWebSocketRequest)
0 J1 ]- K5 |4 X* s, f r - {9 A. E+ m0 _, ?& o
- context.AcceptWebSocketRequest(ProcessChat);
4 M4 m* S/ y( ~5 T& T% m# } - }
- k& u- K/ C ^& H" i - }
9 J4 l+ w9 U% A1 k l/ {) H
l! P/ H, c- `1 n7 H- private async Task ProcessChat(AspNetWebSocketContext context)
9 g8 a& V3 Q) y* @2 U0 f5 s - {
4 c$ [* x3 U- y$ u; R; ] - WebSocket socket = context.WebSocket;; C0 [/ \% ^& Z! T+ s5 v9 ]
- string user = context.QueryString["user"].ToString();
* c, I: l0 w' ~! @: j' `+ c1 y7 g - % h8 p3 `' ^; B8 A& B
- try
9 \$ [3 B8 {& K& O4 T5 f - {
' M$ c7 q8 l, O% v - #region 用户添加连接池3 o! c7 N. P1 Q/ g; A' J _: W
- //第一次open时,添加到连接池中
7 l- E1 P, D9 l h! _8 f - if (!CONNECT_POOL.ContainsKey(user))# O4 y* Z0 n" \& A
- CONNECT_POOL.Add(user, socket);//不存在,添加
g/ R8 z* ^3 h - else7 A v) v$ B2 j9 o( j
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新2 H& |; j) L+ a( l
- CONNECT_POOL[user] = socket;
% }$ F8 E; P9 ? - #endregion
5 c, @1 D' D) E3 K/ M# G" S+ U5 b: l - 0 M4 j8 f4 n y) m$ [* F% f9 U- h. h
- #region 离线消息处理
' e, p7 f4 n4 _$ I2 q* t - if (MESSAGE_POOL.ContainsKey(user))
& \' f2 \/ v/ ]/ L. n - {. {- M) B+ \3 j+ y$ }
- List<MessageInfo> msgs = MESSAGE_POOL[user];# W9 v0 x# Y/ L- t4 Q9 K8 L
- foreach (MessageInfo item in msgs)
/ p: P: r0 c9 T4 v6 j - {
. s1 g5 g3 n2 H$ R - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
) G+ g" m4 ~$ r' k - }' Q" Y0 C7 |; n' O; ?/ ]
- MESSAGE_POOL.Remove(user);//移除离线消息4 w6 Y/ ^5 r0 R7 q; c& W
- }
2 D" Q* o% G7 W( R% V) y* Q - #endregion
, r5 ?( `9 P- ?. Q. o: e - . B* E6 h- P% }* e, ?
- string descUser = string.Empty;//目的用户
- i8 l5 T, j! g - while (true)
& A; |7 D5 z+ g0 l( w0 ? - {
; X6 y2 U& y% {# Q9 ^& V - if (socket.State == WebSocketState.Open)6 U% d6 I4 T3 s- B
- {, o7 V6 y7 h- c L9 |) {
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
2 m2 X$ B q, [6 w) g, b1 C - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
0 F7 _ I7 I; V" J3 S- g - ( Z. I. ]$ [1 h2 L- y: |" }
- #region 消息处理(字符截取、消息转发)+ W- \& i8 x, z- x4 x- Y8 Z! b, S
- try+ o/ G3 j$ d9 J; y! g/ t
- {& y8 \; Y/ m' N. b; b4 h+ z
- #region 关闭Socket处理,删除连接池1 f4 D U7 u6 h8 e9 T
- if (socket.State != WebSocketState.Open)//连接关闭5 V7 q! F+ n% G" @1 @7 p6 u
- {. c9 t: Z; i) G8 B7 H
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池) u4 Y0 `3 q$ i' P0 u$ M, R4 ?
- break;& G \0 T! D I6 s( r7 M$ q2 `( n
- }0 u5 ]1 [. |$ z4 j
- #endregion
! [: L7 @3 S$ j% L+ @9 H' \! I- D6 Q6 i
+ b7 `2 S, B) O% e; x- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
4 s- p4 L+ j& g+ H0 u" Y- g - string[] msgList = userMsg.Split('|');
: V% v& o" R. k9 P4 x& `$ ?2 P$ N - if (msgList.Length == 2)
0 L9 K( r4 d: j+ Q - {
2 E% p# A! o* c7 p' X - if (msgList[0].Trim().Length > 0)
9 x D' K( w( L( \" X) @ - descUser = msgList[0].Trim();//记录消息目的用户" D9 N4 A# C- o3 ?0 E) `
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
1 b2 J1 p% m# d- k. K% L+ ?( J2 { - }
6 t; H" F3 }0 Q2 T - else# B) w4 q! w1 Y/ r9 m5 {$ s+ s/ T
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
# `: E! H! u# J3 K* f( f( F$ }
. v: ?, \( V$ f+ v) C# e/ o- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线' h# T$ h. ~5 C$ e9 S# f8 a
- {4 O9 r) W& q4 K0 h
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
3 `5 Q! y4 B* b: l+ M7 c2 s) I& G0 N - if (destSocket != null && destSocket.State == WebSocketState.Open)
- J/ e8 K& e- t - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
/ \" j C" ?- S0 a$ U9 d - }) _8 [3 J) m' J" M0 Q
- else
* z7 U4 @& m a. N- Z1 P, T - {9 |8 Y( ]; \2 f6 S
- Task.Run(() =>
& `9 t+ u0 |6 {# ?: S2 d - {; t3 ?. y2 j6 I
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
, n; H) Q- r7 v0 c0 U' J6 s - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());& ?9 y+ q3 _9 O9 L* v. {% G
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
, }8 f3 `! R# d( g/ r# k - });
; a4 \/ e/ h2 ]" q0 { E. M - }. G8 A8 y1 i& O* g
- }
: e0 e/ Y4 `0 s" V: Q- I - catch (Exception exs)
/ j4 T. A% @0 ?% J E - {6 |4 P6 ~3 T4 j: o- V1 |
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息2 |' W* C& m- \% k4 ?
- }+ Y/ p+ q" F& p( F( k
- #endregion1 I- S* e+ b5 Z" t
- }
) B- G. I* \. ]' b) f2 f9 E+ p - else
3 ?/ Y) E# L' q9 u - {
& d! p5 V8 P' F# N( ^ - break;
& b4 H& V; ^2 C a9 ~0 n - }
. u: j& f' n; P9 I) l0 N. V/ D - }//while end
# U% z" M5 ?1 K4 l3 x - }9 L& ^; @! y+ X0 v
- catch (Exception ex)
; [5 F X! f9 G& h - {
- C! ]% g/ W% J6 r3 V2 a( c" M - //整体异常处理4 U% h" V1 R5 K# S* V' ~
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);/ ^0 }! G* g* R5 G
- }
0 @ `& \" J. _7 X - }
% I3 ?5 [1 e {) j. X& X - ) x6 o& T a0 M5 k
- + W' G8 e! `( s- W# q! z2 l
- public bool IsReusable6 S. R; F0 n, k
- {
3 {5 ]+ X- K( E8 p+ q - get) f% A o! ~7 [' z+ Y
- {
" s) F0 D6 q6 a& }3 R7 d( } - return false;
* D# i+ `0 T+ P7 A - }
# T/ a1 V3 p) d! D - }
" z0 d( a3 s8 V) K* N" d+ m - }$ F2 P v: j5 C- R4 d! t: f
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
" x0 U- Q* W4 N( j |