服务器端代码编写 1.新建一个ASP.net Web MVC5项目 + H9 ^' \$ t8 w
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;# E' M. o2 G& t7 y. Z5 k9 R/ }
- using System.Collections.Generic;% ?5 |" V" z- ?) U( S- c; y3 W S
- using System.Linq;
) ?. |2 P: f5 s - using System.Net.WebSockets;
* s& m ]/ V4 M3 M* \. F - using System.Text;6 m! K& F" l, t" M& T
- using System.Threading;2 c; _6 B! |: M( f- g
- using System.Threading.Tasks;0 T: i$ e, |! ?6 P7 F
- using System.Web;
. l2 T; j0 v7 T. O1 k - using System.Web.WebSockets;
4 s4 n% s4 v1 U9 ~* Z- ] - 8 [4 c* o* o. ^! \! ?5 U( z: k4 @
% M, u* b. \ g6 C" |- namespace WebApplicationWebsocketHandler* v/ s0 K" q& I, o; o) u
- {4 C; z. I. [" z# m2 `) Y2 C6 y# t+ F
- /// <summary>
! F4 ~& q5 `+ K6 K, f( ]2 n# _ - /// 离线消息
6 [9 Q: v& U4 t- O/ J - /// </summary>
7 V& l$ Y6 e. U) A( Q! b( B - public class MessageInfo
1 R ]- m+ N$ H4 g& H4 l& G - {
& j4 U8 S% H' n0 u" _1 X7 `4 L: E" o - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)" Y w6 T8 e, T w3 X9 A. |
- {8 H' M3 P* k7 b: e( k4 |8 w
- MsgTime = _MsgTime;
* j. w& p4 u3 q - MsgContent = _MsgContent;3 O! X$ X' e8 u2 |( N/ _+ n1 `
- }
0 E( u2 G: B6 t9 G - public DateTime MsgTime { get; set; }
# F+ z2 V6 a$ [% T4 `* y - public ArraySegment<byte> MsgContent { get; set; }
( F. L b5 c, I3 [* ^7 Y' g - }2 ~9 q) K$ ^: k3 g
: p+ l( ]5 q' [2 g6 ?2 m" v! d
: a, u, r% r. c* F- & M/ Z! Z! j: j( P" J
- : d0 ?( ~! Z7 J+ h' T% T0 Z! B, m
- /// <summary>! ^4 k, j0 l. c
- /// Handler1 的摘要说明
. b2 D" Y# t- Z3 w0 E$ j - /// </summary>: L( ?* v, X# s' k4 S! f
- public class Handler1 : IHttpHandler& ?1 |" b- B& w' ~" e' E& e8 K
- {- ~4 V" }9 `% I( ^- x# ^9 {
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池) Z5 R, I" m3 l2 b, Z# u6 m
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池5 F' ?6 j& s9 s: R# O& N9 D/ n
- public void ProcessRequest(HttpContext context)" @" x2 e X" X! w
- {
- ~$ H) n* r9 O, T1 b! X - //context.Response.ContentType = "text/plain";
' K+ m' m7 B/ d - //context.Response.Write("Hello World");- F; T2 Z* [- f+ b* G y2 V
- if (context.IsWebSocketRequest)
( p' r T- Z( l- ?" p - {- k+ V2 B0 q# V# X
- context.AcceptWebSocketRequest(ProcessChat);
. C: z8 D4 F' F5 V9 }; \- U9 }/ ~ - }
4 Z0 Y+ f; |5 N: j$ @9 w% ? - }; D5 L- k9 n! A' t0 m/ N$ d" {; @ f0 Z
- + U4 ^* ]; v3 i$ J) j
- private async Task ProcessChat(AspNetWebSocketContext context)7 G, v! @( e, E5 C8 J0 s, r
- {% P5 F: A" @! I: |
- WebSocket socket = context.WebSocket;
2 _/ j" Q3 @6 q( K" N3 a5 n - string user = context.QueryString["user"].ToString();
/ o/ p) {4 k" A4 D$ T. { - - k) w. L* k. t) r( o) o
- try8 W9 E. h' C) {/ Y7 [/ G
- {8 Z1 H1 K/ T. d2 h5 D6 w! v
- #region 用户添加连接池2 z6 F. K1 q) ?: a) x" W7 k, c6 r7 r
- //第一次open时,添加到连接池中, l% q6 J) n6 A9 ~7 L1 I+ L
- if (!CONNECT_POOL.ContainsKey(user))5 `5 s# R2 v {2 Q; }
- CONNECT_POOL.Add(user, socket);//不存在,添加# ~4 E% A5 N! j4 X) a
- else. |* w3 s2 d/ @6 y, }/ I
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
& q4 J" s- H# e0 s6 ] - CONNECT_POOL[user] = socket;
+ P4 u# j% C* c: L, L - #endregion
( a5 L( h) w% j# k- B. L) R F - 9 L5 M% ^7 ]% p, s& A O
- #region 离线消息处理
& r- s1 ~9 _) ]1 B& \ - if (MESSAGE_POOL.ContainsKey(user))) s0 I* G% U- g! s7 G
- {
: o1 B9 q) C1 K4 U - List<MessageInfo> msgs = MESSAGE_POOL[user];7 S" j2 S" { C' x" n( b" x+ s: `
- foreach (MessageInfo item in msgs); [' P0 W* t/ p6 ^
- {+ x, S! T! h' d2 X! O e
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
" e9 \& f8 V4 {5 i+ s0 F+ ?# G) j4 C( Z - }
2 S, X" O9 d+ D, h6 n4 {& ] - MESSAGE_POOL.Remove(user);//移除离线消息' ]! t2 I! n* Y T4 A
- }3 N; x" q }& C8 E
- #endregion
4 q4 F' K: J; _8 K8 U" ~5 m
: w. C" p2 Y$ z' K Z) F- string descUser = string.Empty;//目的用户
" h' [# |0 Q: l5 A - while (true)
, M! g$ K1 t" B3 | - {
( a5 e' I9 S& D- V/ s% d+ I - if (socket.State == WebSocketState.Open)
$ ^, X$ R1 N3 g4 q+ n: Y - {
) |1 W. y3 N. y8 | - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);2 Z2 Y$ Z% x7 A0 t+ B
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);+ B% k+ M7 h8 u; o
- n# X( P2 |9 S$ s! v- #region 消息处理(字符截取、消息转发)2 R! b# J7 P8 G
- try
2 G0 b N% R0 D. P6 D4 b - {
8 C% ]! a, q/ n5 E" @2 X* q - #region 关闭Socket处理,删除连接池+ p5 G- }& r5 u. W H
- if (socket.State != WebSocketState.Open)//连接关闭
$ X; `; K" H" G( ?! Z. z - {
J3 q. Z4 k( E0 z" r6 d - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池6 A7 _7 G8 A6 j$ T2 h
- break;
: T- i+ A/ g [& z - }) |, s5 t; u0 |/ A; M6 j; M
- #endregion" x+ ]# o5 }9 N- R
- & P: q1 v$ U2 w; {- S
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
; a. D0 ~9 }! n+ }& n' [* q( K( C - string[] msgList = userMsg.Split('|');
0 o+ F1 B |2 h - if (msgList.Length == 2)* x1 V2 p( s, L, k* C- S) D, j
- {
5 s/ h! L8 M0 L' S3 _# v* {. B - if (msgList[0].Trim().Length > 0)' i' P1 k" C( }. [( z/ M/ N; r1 h9 s
- descUser = msgList[0].Trim();//记录消息目的用户
$ E: I" o1 A) U; f, ] - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
& v, W$ N% f+ b3 Z& ^ - }) ~; F+ P8 S8 Q% ? @3 ]7 n7 x5 m
- else) n0 E: F6 I, A. Y& c4 ?# P: Z% g
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
3 Z5 }" w" |3 k& N0 i' P f - 7 H' l' z8 \! A' f( \! g; {+ X( K
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
$ P) n: q* t2 i* G! Z - {4 x4 l0 ? n4 U6 L0 l
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端! e& z ?; G: ]* z* w9 i
- if (destSocket != null && destSocket.State == WebSocketState.Open)2 n% c/ G1 |: F/ h7 E. C" {
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
. }& |6 \9 j; ~- C7 {4 t - }
! ?! T& o; E% v - else
8 J. a+ [8 t! ~0 E) e) l# m9 K - {
+ X3 j4 r$ ]' _8 ` - Task.Run(() =>
5 S( O8 U+ {& @: X# {; B - {
* p/ Q7 m4 K7 R8 P0 x - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
: J/ J# h5 T: e - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());3 ~- Y2 A/ @* _: h) x
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
2 S& l5 e) Q+ h" t7 z1 {% R - });
" I5 j. e5 p! d9 ?" v. F" p - }, z A6 m& N& Q9 Q. v$ i$ I( k" H( z
- }
; e7 ~* o& ], O( S" y% y% g - catch (Exception exs)) i" Y6 R; e2 f8 l8 o* F& r h5 D
- {
: p! @5 l& b' ~0 g0 h: t - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
' n: f+ W4 g2 n, N - }& ~1 X! C4 @' c9 m6 A) a
- #endregion
& X& c$ I/ @) P' q; { - }/ `! W2 a: o* \5 P* P6 c8 X
- else
1 k8 P) p% e. M% l0 G - {
* D: A5 v% t4 y* X1 B. ] - break;% R% e6 _9 N3 r! {% ^" B
- }
7 m& P; s: a: J8 K3 {' `4 @ - }//while end
* y9 f' V0 N0 L- R( Z( T8 m - }
2 i; p3 [6 L* q/ Y: ?# R - catch (Exception ex)
( R8 a6 P! _8 ~9 O3 Q; M9 G9 Z/ a - {
; _! a X( K7 K8 e( H - //整体异常处理
+ h) M/ ~7 r9 b6 [5 A. t - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
( X5 l% ^: L d7 ? - }0 a6 ^; J+ A) b+ j; I( n, G
- }
& u C' I9 N( B$ d+ Q0 _
$ {: u* z" U4 P! \
1 ]( _: q* q$ s/ Z% z- public bool IsReusable3 A: u! t8 i# h
- {
a4 g% W! T6 S& f$ {, l - get6 [5 b. `2 L9 ]7 _* Q1 ^
- {
* l3 _/ E! {, A E; o: [1 W* Q - return false;
9 N; \9 u4 U: ^& ~ - }3 R, |9 ]$ t- U
- }! F7 k7 t( L: b( Q) T- D1 V
- }
: l% M6 h s( G! n* f U4 \1 t/ p' W - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 ! q' Y8 Y! T' g5 p$ X) J
|