服务器端代码编写 1.新建一个ASP.net Web MVC5项目 2 P) o$ I+ h+ z! C5 p' B8 H/ Q; D
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
0 n! i) C. ~; V5 T ?4 b2 h0 P% y2 R: C - using System.Collections.Generic;
& c6 B' {. J6 w+ q! C* L) t - using System.Linq; m9 _ b2 F! O2 T4 g
- using System.Net.WebSockets;
9 W8 a' j1 J& F' _8 Y5 p/ g# ? - using System.Text; ?0 J: z( U8 T
- using System.Threading;+ |4 G, Y+ p, @) C
- using System.Threading.Tasks;
7 U4 z' V, x# _% Y - using System.Web;0 A* P. k9 }8 D) B U4 T
- using System.Web.WebSockets;1 w! u, z9 v! ] x2 \$ p
- & T: j: G. x2 ~, e& y: t. _% i
- 9 e1 P& G# o/ u- B) S) Z3 z: _
- namespace WebApplicationWebsocketHandler
, w J+ ^% U% Z0 z" f0 x7 ~ - {
) I0 U3 ~5 c, k8 d& ] - /// <summary>
& P) @) s7 l1 k5 @ - /// 离线消息+ z2 s& t/ o! l+ f; b R! c6 f
- /// </summary># [% [# D9 ]' J6 G
- public class MessageInfo8 a' w. p/ L& m" S9 ^, U1 M
- {5 t0 Q9 F" d( P& d. G0 {) T
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent) ?: ?$ ^; J) o {& K' K
- {1 }8 r$ j: n Z1 @, Q- P* h# k
- MsgTime = _MsgTime;
5 m3 `* X6 G' [7 P - MsgContent = _MsgContent;+ Y! m( A" B- L
- }
/ _0 [. M! F. L+ g& i+ A, j1 e' q - public DateTime MsgTime { get; set; }
: F* Q0 S" A* G0 R/ W6 i - public ArraySegment<byte> MsgContent { get; set; }8 ]& F( s* E |- ?+ a. Q* d
- }
# D$ @; p3 ]; Q6 u( P - ; n. q% _$ e* d( O
- % m& r- z4 f. _- E9 r4 r5 F1 y
& M" T/ ^, i0 }" S$ D
9 k9 `* v7 \9 |+ Q- /// <summary>
$ {0 a; K. p# y/ h8 F! z - /// Handler1 的摘要说明
2 S3 p: j! Y5 n/ t+ W! V - /// </summary>
* O- l6 c. x- E) G2 T3 C5 Q - public class Handler1 : IHttpHandler# a' g, O6 J3 F5 n( S
- {
( d: U9 |7 E4 q$ \; j) b - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池1 Y" d |2 y3 b1 P8 s7 Q
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
1 {0 n9 s/ A( u- `7 q6 U5 @9 g; x: n3 P - public void ProcessRequest(HttpContext context)
/ k- ~1 K0 H K" \! p4 [6 N - {
. e( g! H# E. G - //context.Response.ContentType = "text/plain";7 k& f0 Q2 Q1 U7 W e1 F* x. h
- //context.Response.Write("Hello World");
2 B2 Z7 ^ E o. y - if (context.IsWebSocketRequest)# Z# x8 H. S$ X0 n6 S+ a% J0 n
- {+ i. D7 n- h" f. x' J) ?
- context.AcceptWebSocketRequest(ProcessChat);; d7 D* u4 q7 t
- } : ]* z( G$ _ K# M# f! {- j
- }
$ ]% `1 [, v2 m) L8 I0 ?* i( \) K - " V/ x: L4 r. ]- @$ o4 c
- private async Task ProcessChat(AspNetWebSocketContext context)
7 s( y/ W5 N8 q: W' c$ l; S - {
+ ? n' h. ^ E5 | - WebSocket socket = context.WebSocket;# |. C' S5 E& c2 y, r" ]/ m* y
- string user = context.QueryString["user"].ToString();
! _( o4 k9 n& U" \- A6 R0 v - 7 J8 ?* P* z( l7 o3 d( d' }
- try
+ k/ i% f' \. i5 |5 N. W - {
. V( g X( Z" g+ X# ~" b - #region 用户添加连接池 |# v" c; z" f" o
- //第一次open时,添加到连接池中7 H8 Z1 c+ `" ?) @
- if (!CONNECT_POOL.ContainsKey(user))/ s) ^6 a9 v0 r% O
- CONNECT_POOL.Add(user, socket);//不存在,添加
( o V5 ~/ b) g$ e( X/ c - else0 H9 P# a$ W) |, \
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新* o& _1 X" G- k( Z0 _5 w
- CONNECT_POOL[user] = socket;
/ |! y o3 D K; E - #endregion5 ?- k1 L+ Y/ }' f, }: U, W; a( a
- 3 R9 E0 q9 J& ^
- #region 离线消息处理, V `9 X. @$ J5 G% t' f
- if (MESSAGE_POOL.ContainsKey(user))& Y4 W( t9 m5 \0 e) ]8 ]- ]
- {
4 Y; J, P5 x& u5 H - List<MessageInfo> msgs = MESSAGE_POOL[user];3 C* s+ @/ A2 ~2 C! z. C! o
- foreach (MessageInfo item in msgs)
' k7 q, x; ^6 }6 r/ s- N: W - {
5 ?7 g% B# ^5 L, `, ~6 h$ C, N, B - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);0 `* H* i1 w: m) r/ \5 T1 J* r
- }4 q% X3 J* v* H' r; W, V
- MESSAGE_POOL.Remove(user);//移除离线消息
# m+ X6 Q' O, X4 P- y3 V2 o# Z* o - }6 j" _. Z! ?4 u9 H
- #endregion8 J* n5 i `+ g4 L" ?" J7 f
3 ^. ~. M+ P+ e2 ~$ g- string descUser = string.Empty;//目的用户
2 j, H' e" z7 k" c. Q/ s' x - while (true)9 G$ [1 L6 R& A9 v5 j
- {. k% n& I% _" R: Y/ O
- if (socket.State == WebSocketState.Open)
% z; d" i0 @. r. b: m' L) F - {# e W: e* H, i M G" i7 N+ ?
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
/ A( f2 {. }/ H: J- h - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);, d& h( Z% j1 r1 v4 u
- , {& ?1 s7 M: R
- #region 消息处理(字符截取、消息转发)% s5 E4 n# v4 i/ {/ M! M+ m
- try4 Q% T* b3 a/ A+ o* {* ^
- {
1 B( O6 i0 n! ]& L7 [7 K1 V9 X - #region 关闭Socket处理,删除连接池( o# R; J2 s' a: s
- if (socket.State != WebSocketState.Open)//连接关闭
: X1 r2 U) G) y( \( S( r - {
8 s" X' K+ T: R, l. Q+ I+ ? - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池' h3 ]. |4 m9 s( o! o
- break;/ d. D$ F9 h+ W3 G6 n6 v- z; }
- }
4 p6 i9 o4 g) m - #endregion1 g) K- [9 K4 u" v8 B
% @0 A" \4 q' ]7 v4 |+ y- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息( [6 }% l0 V, d+ @. P: C; K
- string[] msgList = userMsg.Split('|');" \0 [5 J) X5 f- j9 i
- if (msgList.Length == 2)
, p/ c' _$ R% x$ E - {
/ h+ ^4 w0 O8 g4 U* A% O: M# B - if (msgList[0].Trim().Length > 0)
$ y% V+ o! Y) s3 O2 p, \ - descUser = msgList[0].Trim();//记录消息目的用户
/ F2 ^* H7 Y- V5 B6 F0 ` - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
4 U+ \; U: K% B% _' E6 P9 \- ~ - }
. a: ?& w6 t# J - else
1 n) s0 M9 ~" Y - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
" [! N2 a) u" o/ l
3 s4 n; N3 ^! [- g0 Z- E" w2 v- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
: `; d6 J% n0 M; Q0 x J! p; R - {
, a; d2 C$ K3 V1 o" Y2 B - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端: i# w, o6 b1 {! n" |; p J. C. D) j
- if (destSocket != null && destSocket.State == WebSocketState.Open)
6 e5 }" l1 | A: |+ ^0 a - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);# I2 g3 c8 k" b+ r
- }
. L6 A) t( s+ ]6 n, l1 ]! Y/ l - else
, g2 @4 |8 [: f - {
9 E% e! M" X' I( [( e3 d - Task.Run(() => [$ B& F% D- L9 c7 |- z! R" B
- {: e/ D8 Q- u" l( I
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
& `# S. C5 Q5 y0 s6 U - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());, o0 b k( O7 E6 w2 Y- M
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
' T- o; Z/ C$ s5 E: W% W* M1 V - });
7 y) o0 K, l: t6 m% i% [ - }
. Y$ g% r) a7 w - }
. \2 C! [9 m* [' O8 y - catch (Exception exs)+ N/ N' b% `. \, o% | j* M
- {
1 m' I; [- w$ h4 c }! x' J - //消息转发异常处理,本次消息忽略 继续监听接下来的消息* S3 n* n/ L4 h% D8 X
- }
+ S, j( V1 d7 ~# S% ]( j - #endregion% d9 a% e1 z/ D/ T/ c6 d
- }1 _+ S% r& y5 m" T" ~# w- s2 w
- else# v) S* {2 V% H! F9 N
- {
1 ^, K. U- n4 ^0 K - break;
" D8 l0 e" q' x4 d! t; y9 r+ r - }8 j8 c+ e! S$ I$ K2 G3 [* F! k0 @
- }//while end8 _8 n9 e4 Z4 J9 m
- }5 g& ^. Q0 V! ~6 q
- catch (Exception ex)6 g1 w7 Z t: G/ `1 @9 }
- {
) z+ W4 @" p$ y - //整体异常处理
' W) `: W! a7 w+ g+ h8 X! @$ {5 B - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);9 x i' B1 o7 W+ y
- }6 a: s% J3 C" }- J
- }
! P8 |6 ~( z0 V$ p% n6 v - / n c. f0 O o/ s2 w
- + T' B9 j' G. {
- public bool IsReusable% W1 i/ ]( D" ?' A1 L
- {7 q' d+ G* X0 s2 L
- get
3 L: V! L: F/ C0 A4 y D1 _ - {
; G2 ]3 L5 C% d% R - return false;4 f7 L: k0 n6 ?+ v& ^* `# q0 O4 Z
- }: J- k3 E' N2 _& r, J- ~4 v/ j
- }' N, H5 g4 Z% H! F
- }3 R2 X- o, R- D8 {' z0 R! L
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 + g( T [. H7 ^& n; q4 _
|