服务器端代码编写 1.新建一个ASP.net Web MVC5项目
$ D" Y3 D/ U# p/ i* O( d: P2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
/ A* ]9 S# U1 G/ n, z7 b6 B - using System.Collections.Generic;& K0 _! U6 ~; ]; l( ` j
- using System.Linq;7 {% Z& L0 Z) w6 }, V, {
- using System.Net.WebSockets;/ l; N6 g e) z u7 n, D
- using System.Text;9 v% q5 }+ i4 G9 L8 e2 r% A* _
- using System.Threading;
* }, h0 z! F$ F$ @% @" x - using System.Threading.Tasks;# y9 W( C+ _8 W3 ` W4 U
- using System.Web;# m5 o" _4 d$ ]
- using System.Web.WebSockets;
, Y# y1 h, e4 Y6 |* o2 D - ) Y: w& X. L% h2 t) U
- 4 d1 k1 b! a7 ]) g& r& r) K% s
- namespace WebApplicationWebsocketHandler
( g+ C+ K/ ?7 u% I7 h) A. V5 y - {6 t7 c: `2 C& j6 H
- /// <summary>
' D4 F' T# w: x2 n2 \ - /// 离线消息
; n# `8 U/ y3 ?/ w9 `) Z - /// </summary>
0 a8 q# |; _1 Q$ M - public class MessageInfo
7 ]/ b7 `5 L- Z4 s- [ - {' e. o- Z! m# a6 P8 u3 u' V
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
. B2 K) x$ G! Q& r' u: f - {
# B" T) s( q, a- I! M" E - MsgTime = _MsgTime;
, l- N# x+ a$ \( N3 a - MsgContent = _MsgContent;
4 f+ q% I. j% e$ K5 N' X - }$ e O, Q/ m" o. n2 X5 @
- public DateTime MsgTime { get; set; }
" L0 X. @) m6 Y - public ArraySegment<byte> MsgContent { get; set; }
0 B1 S# l( P6 N# a) U; n - }, K+ k5 x+ J e% b" ~1 @) g
- 1 P' Z' n7 M( L+ q0 q
# E) a; ~2 ]; W6 i- ; t1 M0 j) W: g% R! N
^* h& d1 y: w) F* ? ~4 o1 T* a7 X- /// <summary>/ M$ [: l0 }5 [
- /// Handler1 的摘要说明
' K8 o- Y0 a Q - /// </summary>$ h/ ~" I. y8 F6 S3 B
- public class Handler1 : IHttpHandler% B6 u! U9 A$ q4 o
- {
. Q4 N+ T4 B7 D r$ n - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池6 S8 c3 ?( _) H& L' H" S
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
5 h6 ] G }9 H: A2 i4 z - public void ProcessRequest(HttpContext context)
& [0 |' M; B" l" I - {
( k; l8 f* K3 s& f' w - //context.Response.ContentType = "text/plain";( ^: C( |9 h$ S5 n- T$ P. k) P6 e8 c
- //context.Response.Write("Hello World");
0 |. `1 X0 F" g! V7 V - if (context.IsWebSocketRequest)/ C; G8 W* M; n) K
- {
% _4 H; i) d# Z0 \4 | - context.AcceptWebSocketRequest(ProcessChat);
& l b+ q- e7 w2 d - }
% |! W9 \5 H: } - }
& o0 |, V) W* g) U. D8 |9 }. B- b
: h' b2 z# V8 W5 p+ w- private async Task ProcessChat(AspNetWebSocketContext context)
6 V& F; O' u. A* {& @ - {; k3 r8 G3 A9 D
- WebSocket socket = context.WebSocket;
% e9 v! l3 v( M# z6 H - string user = context.QueryString["user"].ToString();1 I1 V' I3 H( B M9 f% s: j& L! j
- 1 v4 R" e4 A" k
- try2 F7 @( K1 t- [& ~
- {
1 [9 [" _! H. h2 \: w# ]& } - #region 用户添加连接池
: u# T; ^) K1 {+ }0 e - //第一次open时,添加到连接池中
! q V0 [% R9 d7 f" O+ `2 \ - if (!CONNECT_POOL.ContainsKey(user))
7 I& u0 W) I7 c$ B - CONNECT_POOL.Add(user, socket);//不存在,添加
$ G% z8 K) `& k/ Z5 c - else1 h1 h h. n# v4 U Q$ V
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
/ K& i/ M1 \4 O) ?6 g5 _9 o - CONNECT_POOL[user] = socket;9 W4 ~9 P9 |- n* r. \
- #endregion: \: y9 Q7 T. d
* u& \+ P8 N4 D2 z7 g6 k- [$ Y- #region 离线消息处理
6 W0 x C8 O T- F) O3 K - if (MESSAGE_POOL.ContainsKey(user))
$ i- N/ [0 g t5 ` - {# o: l O9 g) y
- List<MessageInfo> msgs = MESSAGE_POOL[user];5 y5 L9 \& q- n. f* p& S
- foreach (MessageInfo item in msgs)- k. J; {3 t+ v# i$ S* p3 J
- {
0 g: _0 g+ R( m/ e- K1 C; ` - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
0 X2 m5 v& k, c$ v I5 x1 X6 G/ ~ - }
6 C# r$ o8 |; `% X - MESSAGE_POOL.Remove(user);//移除离线消息8 }3 W( A. }5 ?$ X& X7 L
- }
0 F) ]/ ] M& ]% P - #endregion9 V+ t# s6 V! r( c
- # B7 c3 J7 B. T# w. G- w
- string descUser = string.Empty;//目的用户
' n/ p# T* h- s/ ^- ~) H - while (true)9 @, i2 x$ w* g0 g5 B6 z w: _
- {
" \# o! w, W' ^" M2 J) w, ~! L - if (socket.State == WebSocketState.Open)/ Z# A ~# }1 i& V" F
- {* G* S0 A/ [; U4 D% [! C
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
1 p# c& V4 S, h/ U# @ - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
8 A$ I2 P1 N1 u. q4 P* f) | - 7 v% C, Z/ r3 P" h
- #region 消息处理(字符截取、消息转发)
% y! x1 E6 f& l4 }! t- Z% r - try7 U3 d" E9 j7 P* w i8 y8 q
- {
, v) s6 }$ e( @ - #region 关闭Socket处理,删除连接池- G# w! i) b6 t3 A" F2 b+ I
- if (socket.State != WebSocketState.Open)//连接关闭
2 m! ^ f$ z: [0 f - {
3 v$ p9 @ \0 p; W* p9 O - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池8 O# `5 w1 j% B# D* M$ J
- break;1 O2 ^( _ ^. ?1 Z: J9 n
- }
& Y" J' Q/ _/ o/ U - #endregion! h, `9 x6 K* B+ e- _
- + R/ [/ i& f' D u% Y
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
, y6 n. S5 C/ H0 C" Q6 q - string[] msgList = userMsg.Split('|');
* Y( n! o3 C+ H1 _2 V0 { - if (msgList.Length == 2)
& e. d! _0 s* @) U - {
. G; C) h4 y& i2 M8 C4 J9 d - if (msgList[0].Trim().Length > 0)2 T7 q2 P+ Q1 S# [% R
- descUser = msgList[0].Trim();//记录消息目的用户
1 N: p& g/ K. U/ b! k6 `( z - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));) k' v1 ^9 k. N$ r9 h
- }
4 j( n, p" x8 S% j" Z( J- @4 l; j - else
( _* C5 `! s1 I( I& m( u9 S# N - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));1 R8 y6 j- W# F7 {
# K: f5 `/ z- M2 B: J8 }# Y- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线- @7 d+ E+ |4 e+ T2 L8 u' n/ Y
- {
/ N6 \* N3 f' T - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
0 m% Z; K' r8 S+ c% F( b - if (destSocket != null && destSocket.State == WebSocketState.Open)
+ v' r' J9 ?6 n% M - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
; N a! [2 T/ u+ O: }! U8 f - }2 _+ q% x" Z4 b& t ]+ Z5 E
- else& N1 q g; K: V" ~
- {
2 p- @4 f+ `% V! f7 d! [ - Task.Run(() => z3 V7 ^" f: r" P6 ?8 A m
- {
' _/ ]# O1 {( r$ V% h. O - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中9 G1 P# f) b j# Z# ^% I* ?
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());9 n. T' V) T, m# o3 H! h" k3 _
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
" V: t6 j; f, X+ u4 u5 {& K) r' I - });
. F* G; d; z: |9 B* [+ ~5 J! k - }' | A H, ^/ D
- }
8 v+ l5 u1 x0 f0 W) ^9 p7 f' V - catch (Exception exs)/ Y% }7 }- C9 M% A
- {
; s3 b. A! i% M0 U: S4 `4 L" H - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
# u* w+ A. u% q& v) _ - }4 H0 Q; Q7 ]' ~5 e
- #endregion
' m, \1 G O9 [' y6 [# t - }! b8 e/ I' k4 p, A2 v* N
- else
. w/ S4 p9 F( ^# @ - {* }. y& Y5 v) l# C, Q# Q9 D1 s0 @
- break;$ q, I2 h: ~1 `; X7 o
- }0 G [3 h! n# w" M% F, O8 v
- }//while end% ?1 ~0 w* b& C( d' `+ x/ U) i
- }& e% \6 ]' j* x5 T
- catch (Exception ex)
$ s- Z& R& O# O" R5 R# t - {
3 K1 \6 O# H j- r4 K0 a- K - //整体异常处理
u. [+ s! Y- h3 q2 ?( n" {; e - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
2 z% \1 S1 M( T2 ~$ ?8 I' z - }
: ~% P. ~! C& Y; M - }
* Z" o, {# S: M! U9 E. d9 F1 i, n+ i7 @ - ! W7 W7 d" U6 o$ o
$ H$ T U! S, f7 X% |9 T: t- public bool IsReusable' F* E3 l6 a' Z# i2 ?' H2 b4 l
- {- w5 G: {8 n5 N- t8 ~( b/ j
- get& o7 a, }+ f0 P% X8 D# l2 U3 y! {
- {1 N$ X8 s8 i: b4 w( w9 c
- return false;6 V% x3 ]. X! y6 c0 d
- }
n" w5 x( N8 {, J4 T2 {! g6 e - }
5 }6 ^4 C) i' e( o+ `; d" y - }# o7 B# x# N2 d3 L8 f/ c
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 9 P0 l6 o% H! j. K
|