|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
& d; }0 c) }, e1 h! t) B' p; I M2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;4 i3 ]0 V% @* I5 v l
- using System.Collections.Generic;
* V% G4 x9 g: _0 \. C9 q, Y" j/ R - using System.Linq;; u+ e( q+ l* t1 x6 s/ }
- using System.Net.WebSockets;4 n; d, W6 _6 E0 ^
- using System.Text;
G' P; O5 t9 Q# _0 } - using System.Threading;- W$ ^5 u& B1 @- V9 R9 `% D/ d
- using System.Threading.Tasks;
# L, t% L( D/ a- v, ]5 A0 ^5 U - using System.Web;
* \7 }6 ^1 P% A* n) M' u( Q7 M' \+ h - using System.Web.WebSockets;! v0 p* ^# H; t+ x4 T3 `
- . F5 u$ z. D Y2 g$ n$ p% D
- 3 P' J" u/ h+ n" E4 z7 h
- namespace WebApplicationWebsocketHandler
3 U6 D; U* n y, ]4 f - {) |9 D, V$ o5 [# b
- /// <summary>
' T' b% a% z# Q' O0 u. J - /// 离线消息
/ k; P; w# G, W i - /// </summary>, T# ~! O K5 @$ z
- public class MessageInfo4 W# k- t6 I6 L. W. C) T7 P2 L
- {
5 e9 m$ E1 u/ H# L. R! r. r9 I' @ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
: X" W8 I, J9 H/ E$ V9 D5 _6 e - {
% u5 r* g, ^" K3 t# M - MsgTime = _MsgTime;+ F+ }+ [+ {; n
- MsgContent = _MsgContent;* W! ~' A( V0 X6 i2 \
- }
1 e- }7 F" j) ^. `; P. s( E" ~ - public DateTime MsgTime { get; set; }3 U1 ^ K/ j- L2 }1 K+ E+ d
- public ArraySegment<byte> MsgContent { get; set; }) ?% |+ l! q. N6 X& z
- }9 T- S S$ J* @
; S/ F% b7 s0 ^
. u/ L: h8 _1 N2 a- W% c- . p$ v. h5 [2 e3 O; @! V @
- % C, I$ |' q% S$ L) C- D2 z
- /// <summary>
" j; h6 W/ F% a& N - /// Handler1 的摘要说明5 V& D& b+ S' p* o. S6 {
- /// </summary>. ]. {" }% Z F1 }
- public class Handler1 : IHttpHandler5 N1 @4 {' g8 j$ O# l
- {
U. [6 g3 p1 C - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
$ s/ f4 ~$ V* A- g' p7 l8 y h - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池9 A( H2 K4 B2 q3 C: x& y
- public void ProcessRequest(HttpContext context) F% ]% b1 J3 N& T: n1 D! P7 u
- {/ ^' G F/ H) ]& t5 {; k
- //context.Response.ContentType = "text/plain";/ P# A% ^8 p! d% K, g3 w) \
- //context.Response.Write("Hello World");* X6 S: ?6 R# Z/ T( J5 z
- if (context.IsWebSocketRequest)* V: |) }6 a6 n' \: z4 G
- {
( R+ z6 V g7 D2 y9 L \; v0 B - context.AcceptWebSocketRequest(ProcessChat);
) n; c2 S9 @. ]# f* n - } ! q! p, o9 o* u
- }/ L1 V7 j8 B% x
- " h4 b/ r- I; ^( p! ?0 J
- private async Task ProcessChat(AspNetWebSocketContext context)
* p0 [; B) w5 b4 k$ y - {0 n! G8 T9 V6 J) y( X
- WebSocket socket = context.WebSocket;
$ p" g$ s2 x6 ` \ - string user = context.QueryString["user"].ToString();9 W' y! y: B: k) \$ x
- 7 Z: a L+ p" N5 T$ _4 }
- try8 R1 S) w! {2 y; M% f6 T
- {% G; [' B4 ]8 i: u1 p2 e
- #region 用户添加连接池/ S& ?7 s0 @2 T1 m$ T
- //第一次open时,添加到连接池中! S$ W9 H3 {6 W [7 d0 v0 H9 c8 L
- if (!CONNECT_POOL.ContainsKey(user))/ P* d8 _" L9 b& `
- CONNECT_POOL.Add(user, socket);//不存在,添加
; N2 v- P" ]* H# ^ - else
6 G# I2 u, E: |: U% z' F - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
. e. h2 s2 U$ w - CONNECT_POOL[user] = socket;6 f+ m8 }' O2 K- q% ~
- #endregion
: W) W" F* j v8 s - 9 r0 D2 R5 H5 G- N
- #region 离线消息处理) Y t( V% ]( M
- if (MESSAGE_POOL.ContainsKey(user))$ \2 e* r, R7 @( {: X. @) l/ D
- {
( r* J# @ o) W! X7 m% `7 a - List<MessageInfo> msgs = MESSAGE_POOL[user];+ Q# O+ {, ?1 u/ e( i$ z
- foreach (MessageInfo item in msgs); @/ R8 [* O* p5 m. a" `
- {. l6 f4 }4 d: q$ i* A3 `
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
1 B5 J6 t8 r) @: k) w" c - }
6 l4 ]& }. `9 D" K. e* o - MESSAGE_POOL.Remove(user);//移除离线消息
+ G& K' m" g5 W+ @4 S - } L+ F8 h) Z7 E! Y( f9 p. v
- #endregion! |2 O- y4 E; g) {, t% V
+ b' ]+ V8 z# A! j0 r- string descUser = string.Empty;//目的用户, F# L! t8 ~$ h8 D0 D/ q: e+ Y) q% I. X) n
- while (true)
$ q* x8 N* c# p7 ?- w* S - {! o5 P" w: B1 K7 Q; O0 s/ B
- if (socket.State == WebSocketState.Open)
7 y0 }" K1 e2 [9 b - {
# z% @1 y, _ e5 @5 Y6 } - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
; r6 ^9 j9 b' e( u( B3 v" V& @' U - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);$ H9 n8 c5 K: ]5 t* e! y3 S [; Y
+ R* `8 T5 s1 L3 [0 C0 G) s9 i0 A1 ~- #region 消息处理(字符截取、消息转发)
; C* y( k2 ^2 z - try& o' p5 K. ~9 _: V$ t8 t& @
- {
( I+ I9 r1 I+ f+ n) l4 Q. l - #region 关闭Socket处理,删除连接池' W$ E$ q2 N- @4 e
- if (socket.State != WebSocketState.Open)//连接关闭$ Q0 j/ h( g4 g; G
- {4 b8 b8 ]5 ]6 d3 D4 c
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池4 W; Y$ S2 w8 N
- break; Z1 x' V! f8 x$ g# D- u: e
- }$ w8 c; _. m- K0 K
- #endregion$ y* U$ Q4 _# t6 U4 _
% B5 _9 I H; C: r* S+ D$ o- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
! w3 _6 o. s d( ~7 ^* T - string[] msgList = userMsg.Split('|');6 w- {+ P% m J% i3 x# l. f# c
- if (msgList.Length == 2)
! K E u) y) p - { S. p8 H8 r8 {2 e1 H Y2 B
- if (msgList[0].Trim().Length > 0)
) F; q, z$ B! ~$ T - descUser = msgList[0].Trim();//记录消息目的用户
) `( u2 M$ T& V [ - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));. \0 F2 \) J- u4 C' \
- }
5 }- ?4 L- h' Y' g - else3 F6 W% I# l7 r! T; c8 O; m
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));5 l, o" s5 ~/ [* s+ j/ O; \
- 1 {# j' W" q9 F: E
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
/ k' B7 G- x: e" m! } - {$ k+ q( E! v4 f) I1 }0 V/ U
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端. u" I' f+ A6 m5 o, f9 \% L
- if (destSocket != null && destSocket.State == WebSocketState.Open)2 c& n2 P, V3 O8 U1 d. X
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);* n# n$ s$ W" }, k
- }9 z. A, M4 M4 ^) j u
- else; I- R% N3 y8 m. w
- {( d# m2 m& G9 G' S& j) U j0 v
- Task.Run(() =>9 h8 Y8 W* A2 m/ O! }2 T9 O
- {
0 [/ `" x' c6 ?+ q8 r/ @; a - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
% R" S3 w- g9 q - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
5 c3 t7 Q3 R) @. {1 v - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息3 V1 G3 L! r: W0 s; q4 X/ `
- });
; S8 y' P2 P& I8 W# D- @) r - }
8 L& F0 r: X7 t# I3 x7 ^. K5 C - }" Z4 g5 y+ v) C3 a
- catch (Exception exs); p9 E' M" W5 K. k% t- R4 A' |4 o
- {. w! I. ^2 k* u" y# v
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
8 D* _- t. `$ s2 K# z8 q h5 ] - }% I* a/ m/ ~3 `/ D) l' Q) l9 x# X
- #endregion/ B8 I0 H5 [7 @0 x
- }$ y; A9 i8 O0 c, Q) ~; P6 _% }
- else6 b: O2 l1 z2 m; _" \8 ~ F
- {
0 P& |% x' }' F+ z - break;
( V( B/ P1 t7 w- ^ - }
& J% b. X2 n7 h' f8 V - }//while end/ Z3 U m9 y7 y9 C
- }
b2 J6 \4 a* n! v; P - catch (Exception ex)2 O3 M' K2 t. U+ y% c/ P3 B
- {
9 @ A+ v3 |8 H; u0 s - //整体异常处理- m! T- l4 }8 L1 H9 U
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
_' X" g3 t( s: r - }
- v i3 V. ?1 L: J - }, Q6 p6 w0 d9 ^; O
# M: W# o1 X2 ?+ S# n- 2 x* S+ A) a* i" F, {- `
- public bool IsReusable }/ G# s* W& h0 a8 H( M/ W
- {
# Y1 ^. x, |) t0 Q7 m4 g$ l - get) w! n1 m* V+ g
- {
3 ?3 E' e$ W" O - return false;
; G9 S( l/ j! n0 k% Y - }" M% D# a& X& ^ Z% E
- }) f4 {# G. G9 K4 Y0 N
- }
; ^$ z& K. u: {& V6 `1 k) k! B+ f - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 # U+ ^& V. h' D1 I, `
|