服务器端代码编写 1.新建一个ASP.net Web MVC5项目 5 m; p6 q2 U& m4 ^/ ~! x
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
( M3 S$ i7 F; X8 C5 p# k2 P1 v+ ` - using System.Collections.Generic;
& L' P+ I: P! x( Z$ w3 w2 m8 M3 T - using System.Linq;
$ t0 a4 P1 t. K8 L8 }, Z - using System.Net.WebSockets;/ G9 \& y% L9 I1 l
- using System.Text;
' T+ i3 N+ y |0 m. n& |/ [* w* ^' L - using System.Threading;
' E! ~' K. R; d- X& X: U - using System.Threading.Tasks;
+ g' ~0 C: ]0 g! r - using System.Web;
# l0 B3 N. I' p( x" C - using System.Web.WebSockets;' g, U/ `; @: g: @) R
- n2 y/ K5 n" A# _
- , v& i8 c! E7 J. I
- namespace WebApplicationWebsocketHandler
( o) J% E, c9 }# k2 Z) _ - {
" _' @0 f8 Z+ ^- v% @6 h3 V - /// <summary>: G. U2 B4 M+ E. l& |2 @
- /// 离线消息
* g5 h4 s) {7 d* N6 M. I8 R$ x - /// </summary>( {% ^+ f: y2 s4 g9 u( Q3 e% _
- public class MessageInfo
2 _0 c( o/ I0 K - {
o: ?/ k6 V8 T6 x - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
0 Y# s! c, A$ @ - {
0 `# \& m5 k, M3 V - MsgTime = _MsgTime;
6 h0 O0 y5 F: y* X - MsgContent = _MsgContent;
& q5 Y$ |5 N- l# t- F - }$ I5 Y( F3 n' y
- public DateTime MsgTime { get; set; }; F, \+ z- L' V) G* g
- public ArraySegment<byte> MsgContent { get; set; }0 U9 @$ L- ?/ Q
- }9 B# F! B! }6 L& ?
- % I" {" P Z5 B: W
+ N8 M% M3 P n( O" P( o- @0 b
) A" x o# w$ F/ X1 ?1 H B( p- 6 y2 j1 ?/ a* C2 Q, o- _7 w; C6 c
- /// <summary>4 e' b2 H& H r' Z& ]4 ~9 ?
- /// Handler1 的摘要说明
+ O; r1 O4 T/ x3 V$ t( |& l! x. m+ m - /// </summary>) U' E* }+ k+ E& C, Z
- public class Handler1 : IHttpHandler
. g" V* ^7 O) z% w$ v$ | - {
* u! n+ d4 `; D2 a7 M - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
- {* |/ p, ^# x - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
6 w y( }: B+ W - public void ProcessRequest(HttpContext context)
, F6 `( f& r; |0 l1 T - {
4 s% g0 _6 b s5 ~ - //context.Response.ContentType = "text/plain";
; N- d7 ?7 E3 R Q- Z9 C - //context.Response.Write("Hello World");, |: j T- G# J d o7 o
- if (context.IsWebSocketRequest)7 C. w P& t! K, M. P f
- {+ \+ G: R) n' I6 W* Z) q
- context.AcceptWebSocketRequest(ProcessChat);8 h2 Q7 X, P9 n# C5 d8 _2 W
- }
( C0 e/ N& d8 D, o& G# P - }/ t" V0 x( z1 ?; {: d4 C
" h$ s7 d8 i1 _) X4 {) G- private async Task ProcessChat(AspNetWebSocketContext context)0 t# e2 N5 d6 y* L
- {
+ g6 W; H' B) l0 }! Y& k - WebSocket socket = context.WebSocket;
3 q1 N7 g; m+ k' W) c" R3 Z - string user = context.QueryString["user"].ToString();
, n# F) F) c4 J7 z6 T
, N% Z+ T7 H7 E# y% I% X/ k# c- try; ^* f4 f: U7 C5 D5 A
- {0 O) t; x' O: ]$ n# Y- j: `
- #region 用户添加连接池
- a& a: B! T( D @/ u0 Y( ^& l+ C1 O - //第一次open时,添加到连接池中' ?4 Z6 W7 L8 H7 C5 b& R
- if (!CONNECT_POOL.ContainsKey(user))8 ?6 k% b2 |, m9 q- v
- CONNECT_POOL.Add(user, socket);//不存在,添加
4 \0 f8 e1 k5 y! d& |8 t* { - else4 V" `. [! T; ]' U! J5 {% }
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新9 |3 g( e3 P9 I& }
- CONNECT_POOL[user] = socket;
5 u, J a1 \9 _6 u0 U - #endregion6 q! k+ A* x, o! N
- j. I0 P# P# @; g7 E& ^7 \
- #region 离线消息处理
' K8 U6 z" I t5 s# c7 h - if (MESSAGE_POOL.ContainsKey(user))# g T- c9 d% R+ w* |6 }
- {/ p" r+ v d! U6 E) @1 r9 l! b
- List<MessageInfo> msgs = MESSAGE_POOL[user];) e( f9 X3 h5 s) ?7 G# x' j
- foreach (MessageInfo item in msgs)1 R. }- e) x$ H7 t" r/ ?; E% a: K0 p) S
- {& s, o; U2 H( [" I
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);4 [, Q5 s4 C* O. w: \
- }
- S. U2 z% T; c& ^ - MESSAGE_POOL.Remove(user);//移除离线消息; }/ y+ E. n2 n
- }
4 N; m1 f0 t" y6 h. D - #endregion
5 t, u+ Y) d$ u$ r) V0 F6 l, O! t - 4 W1 m/ c# M+ |8 s; n2 X
- string descUser = string.Empty;//目的用户 a4 Q6 {& Q0 R" O( x
- while (true)
# {7 C- Z4 i. S7 w2 D- V - {
6 B: I" |, e+ w8 C - if (socket.State == WebSocketState.Open)
0 V. j) G6 G: U2 H+ z - {
1 Z: Z0 s8 {" d; l t - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);" w) e6 A5 N- @8 {: y; Y
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
) w) ]% _% R; D$ s5 x. b3 `- S ~ b6 ]
! F' A9 u# x% c! a; b3 `4 n1 u- #region 消息处理(字符截取、消息转发)
; N9 `$ j8 t7 m1 t g# i. X - try
, g" m& |: F8 T \- C5 u g" e - {
- F1 V! y& Q/ j* H* F# K - #region 关闭Socket处理,删除连接池
0 O0 ?" z3 u6 Y* x3 K, \9 ^ - if (socket.State != WebSocketState.Open)//连接关闭
) s# ]' e' o t% Q - {
1 N9 E' n/ H7 U1 j - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
9 @7 x' n/ z& a6 m: ~1 { - break;
' m m5 v1 x) Y! _ - }8 F$ h2 @3 p' Z0 X" d
- #endregion7 d: R% ]3 [4 x4 a
2 X) D0 p, ~! U: b, e: y# [: w- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
. r" P% v9 q5 f5 Q Y' J$ h - string[] msgList = userMsg.Split('|');
( c" X" D& P* k R3 y2 D9 |: f1 H - if (msgList.Length == 2)" o7 [, P, S: X+ y
- {
, V# ?0 w' c; _2 u9 t( a {4 r4 a6 M5 s - if (msgList[0].Trim().Length > 0)
4 J" C. G/ V# H f - descUser = msgList[0].Trim();//记录消息目的用户0 k2 \- j `& Z% j& K) _
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));" L& m9 m: g( n# p" e
- }" z+ s3 O4 Z/ _" [! ~1 V
- else
1 t+ j$ {. B/ H( _6 I/ ? - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg)); k2 m0 [# \( S J# I4 r# n. l
- ' p, H& {- [9 M1 A, R$ l9 V: V7 {
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
S3 I' m5 R" P+ G; a - {1 d* c5 x& F; b7 V
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
8 c/ g, Q& m- M5 o& @8 [; r - if (destSocket != null && destSocket.State == WebSocketState.Open)4 ]" Y0 u' _, k/ g# J# E
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);# T0 ]5 W. w- l" z+ K
- }9 z+ j: _$ K/ D% X
- else$ g2 x) ?+ E! R: w9 b# U
- {
" e9 T2 X6 t4 L+ {- N - Task.Run(() =>
( W! q/ [1 G+ z) P% X0 Y - {
' R) o8 p+ V. ]* r: S7 e# y- Z0 ` - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中9 H7 }8 [6 L$ @# \0 |& V
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());2 I3 b2 ~$ @9 F; M0 M& c
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息+ o+ b% t3 i5 E, Q
- });8 K/ {1 \: z. t% c8 `
- }! n# Q5 D8 D( {# H. s j9 L
- }
4 e* M! Q9 D& `5 @ - catch (Exception exs)
2 o% s6 L6 v9 W - {- h4 p7 N0 j3 D# J; @: n
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
{( q2 J7 B/ A. t6 ^ - }/ y9 n, d W4 @; e0 U
- #endregion
( B2 r3 O2 u+ I% r) G7 w1 H* I& N - }
* `+ n# ?- z. J0 \) k9 i0 C% c - else2 U A% |, M, D
- {
W5 J3 {- r( X# l+ z p5 f - break;
2 B5 w( _$ ?& j' `% T - }0 b4 Q( l' U% Q$ q) t
- }//while end' h, I! k' w9 B8 x% P( c5 O
- }3 I% S+ y, a% x0 n
- catch (Exception ex)' l! i4 c3 n9 n8 }) Z9 o3 t
- {
. H- Z0 V4 G. [ - //整体异常处理
" t) ~/ ^+ H+ i& h. n - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);4 b/ P7 [1 m, K
- }
& H8 ]& f8 e: ~8 \ - }! |4 F, C. i8 p) z# W
- 4 g$ j9 t! q* v# S9 }" G p
- ! J# M2 S9 F# W) G- S% d
- public bool IsReusable
3 D2 k4 M: u2 H. U# F |2 n - {" q i9 i* y4 {+ G
- get: V% X# n- u6 G) @
- {
3 r0 S: k! h: s3 _ - return false;
& w- x$ t% l' T# w5 ^* w* w1 H/ M - }
" i, }! a0 o7 d4 K6 I - }5 W5 q% T/ @5 s' [; r9 a- ?5 r0 \
- }9 w i6 p) G% `5 i& A& L
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
% f: s p3 x/ I" v |