|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 - b9 e7 A) H4 k9 d& `
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
* i! S+ F7 \/ n: R; l - using System.Collections.Generic; B1 c! m; ^8 V& [
- using System.Linq;
+ s2 j; o3 Z: `' v. a. G4 d - using System.Net.WebSockets;* @. z# \& n- G
- using System.Text;
6 M, t! Z5 N& I - using System.Threading;
8 k4 U0 h, x3 D7 z/ i$ B# X2 q0 D - using System.Threading.Tasks;
; p) ]) \0 S0 { - using System.Web;
1 u- ~' ]% R+ }: a- x; B - using System.Web.WebSockets;
6 W; D: G9 _. s" }' x - . O H8 j8 S% N- o
9 \1 b5 u! |5 x. M/ c- namespace WebApplicationWebsocketHandler
1 T* s5 G N; b; N8 R+ Q& o - {
, f. A/ m8 D: o1 k2 z( D - /// <summary>. A0 [: J5 g1 ]1 ?1 _) h
- /// 离线消息2 ^* B5 i* T9 z& O
- /// </summary>: I/ V5 |! z# S6 z! H
- public class MessageInfo
/ X4 t' d6 [- `# c# n0 ] - {
Y7 T' J9 E8 \2 F' n4 T - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)/ j4 q- Z/ a5 N& l. g0 P* {: U
- {
$ k/ ]" y7 t6 E0 N" l. \ - MsgTime = _MsgTime;
+ p4 B. G4 c. C - MsgContent = _MsgContent;
) F& P9 I7 v6 b( R0 ^ - }
2 l/ n- b- j T# l z - public DateTime MsgTime { get; set; }
6 x0 H$ ]' n( a' \$ T - public ArraySegment<byte> MsgContent { get; set; }
& @. m, D; i# i+ N0 a. B5 w - }
3 H2 H$ \/ K: E - 8 T% X% F+ z$ p$ X+ _" a/ O+ N; t; F
. b5 F, G5 z2 l8 h: i/ O; v, i5 R- 8 a1 H: W6 W/ H
5 d+ B# O+ C K# {' T, e- /// <summary>' ?9 O/ d! Y; F( K) T. ^; k
- /// Handler1 的摘要说明& a# C6 z% p3 H
- /// </summary>
- }1 }7 V' j3 O1 {! u - public class Handler1 : IHttpHandler" j9 O0 Z6 F& @1 t( g) }& J+ [
- {
' r+ Y1 Z# v, D% P) l: e6 _0 r - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
8 J R. u. @- ?6 I4 e - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池2 W9 y! [8 ]( ]2 c# n) N
- public void ProcessRequest(HttpContext context)
( v, E+ w: Y9 t7 G6 ?1 ?3 B - {" Q% `" I6 o& S5 b
- //context.Response.ContentType = "text/plain";: g" a8 S! I z7 |% I
- //context.Response.Write("Hello World");9 i4 O4 ]3 s4 o' b
- if (context.IsWebSocketRequest)4 j& e+ y' h1 @3 l; {/ {+ @! R5 R J
- {- f9 G8 M% s* P+ G
- context.AcceptWebSocketRequest(ProcessChat);/ u- E8 j2 U; P! O4 \9 ?( Q
- } " \! T2 m1 ?$ z
- }
/ S7 k" e. ^2 l" C0 X( ` - 1 \" N ~4 g2 \0 J" I. X
- private async Task ProcessChat(AspNetWebSocketContext context)
0 U) ~: Y ~ ?) f5 @ - {: E8 F' P/ }3 P) v; `, Z7 N
- WebSocket socket = context.WebSocket;. O" e$ Z1 Z/ K( {* p
- string user = context.QueryString["user"].ToString();
0 T- [) ]9 I3 h - , w, ~' y4 u" y' F& g: F
- try) [4 O- A0 V3 B7 Z) b/ |* x. d* }
- {8 F T' S( Z5 N7 u8 S! {1 Q
- #region 用户添加连接池
/ G8 }$ m9 I+ z) G+ U- R - //第一次open时,添加到连接池中4 J; h$ u' U$ u+ W7 F P
- if (!CONNECT_POOL.ContainsKey(user))
! [" F/ U ^' Z% E: [ - CONNECT_POOL.Add(user, socket);//不存在,添加" s U$ Q& B& |+ {& V" q2 S3 {
- else
# A; ?& Q( W! [7 k - if (socket != CONNECT_POOL[user])//当前对象不一致,更新+ F: s8 R8 c" \
- CONNECT_POOL[user] = socket;
4 Q2 X. L! ?9 w- z- g8 P - #endregion
2 x# o1 R( B, D) x - 9 {4 q" D V0 E+ N J( s
- #region 离线消息处理# r1 D' o |, W! _& j
- if (MESSAGE_POOL.ContainsKey(user))
2 a4 p2 [/ {3 x4 Y4 b9 e: k" h - {9 b3 a& Y% Z/ C
- List<MessageInfo> msgs = MESSAGE_POOL[user];
. W- f1 o0 d; S$ U! O% ? - foreach (MessageInfo item in msgs)1 K) N1 @' b1 }" q
- {
+ i7 z6 L1 V9 n+ c& M9 o5 I/ [7 x( ? - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
0 @1 E2 _* Z0 ^0 B+ q: D. C9 s - }" o/ I$ l+ L, ^
- MESSAGE_POOL.Remove(user);//移除离线消息0 t1 m# e- U! a' w$ \5 J
- }
8 `1 |4 S1 P" L# n& H8 w6 Q5 T - #endregion% v' X: v% o( d# Y0 p7 w
, }. Y" m: L, @* i) A1 ?/ a- string descUser = string.Empty;//目的用户
- P: t6 k. ?) o" Z) E8 k5 E - while (true)
5 o1 C7 `" h- V" |5 d - {& `5 W; s3 h& S
- if (socket.State == WebSocketState.Open)1 M7 S! U: D' U2 a/ D; V" D
- {
1 t, a1 @6 g. d+ p - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
3 O* {1 O' Q* T7 i - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);6 r" X/ a( e' E5 E# _5 T; G0 S
5 e* k- R6 r1 r4 u; V1 J3 T7 P- #region 消息处理(字符截取、消息转发)! k8 Q; h! f& \: Z
- try8 A5 P3 I% X# ?/ x
- {: e2 ?1 W% S( p0 T0 i' `# w1 H& @0 s
- #region 关闭Socket处理,删除连接池
0 N9 V! |1 S, \$ R; _/ ] Q - if (socket.State != WebSocketState.Open)//连接关闭
& {# F; b! v3 P - {; k: f1 u- b5 a$ h$ V* W- E7 ]* a
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
3 z _) r8 p0 T; V - break;; z; F) p, m$ w. X: H# i0 r5 A
- }
w' Z& w9 f+ M- v* V: S - #endregion
+ {% F; U# {- ]: @; N3 X, I& l - . k/ f6 Y) F1 ]) f
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
4 d! M" C9 A7 Y9 E - string[] msgList = userMsg.Split('|');
7 G- O: y4 Y( p# A4 ?/ Z7 [& M9 K - if (msgList.Length == 2)4 O' s% x; k$ |6 ^
- {
w! u! L& r! C1 T/ x. `" } - if (msgList[0].Trim().Length > 0)
% ~" @5 t* q b- M% s, w. t - descUser = msgList[0].Trim();//记录消息目的用户
X! d& Y" W% w7 X4 V8 g - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
$ C6 P6 N9 W! v6 A+ z- i, n C - }
5 G# b7 `6 Q( z- i! n9 Y' b" a - else
! i; [- K6 k( q6 Z - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
; m& C- G( G5 z8 i* ~( O! v! { - # x, x, W3 M. Q) U- S, @, Y
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
4 y, Y( w- V: }; \2 t: P% _ - {8 t4 Z( H, I5 _* z ^! S; T
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
- j- z; y; Y% h" Z: K/ o - if (destSocket != null && destSocket.State == WebSocketState.Open)
' w( N2 _' w% }, d; k) w - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
~9 I' S+ B, d& [ - }8 s& k1 u8 h1 v- O; ]9 h
- else ^( k2 @& I5 ^! v
- {' e* R( z3 O8 f7 m
- Task.Run(() =>
& p0 q6 m2 M4 E/ J* B6 D. V - {& c, N L P& M
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
/ l+ J5 w6 O q; z5 Y x# S - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
5 l/ A+ j% h p6 j4 w) V5 ] - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
) ?4 u u5 z8 E4 P - });: |# [1 `( K3 K- e/ M: S8 a4 N$ C1 H* h
- }
4 Q8 [ r& C9 o/ @1 Y - }! l9 @+ s0 C0 t2 U- f
- catch (Exception exs)% v4 c8 f& W8 m* c
- {
! Q9 g' y5 E6 q7 X) v6 z - //消息转发异常处理,本次消息忽略 继续监听接下来的消息5 `0 d7 v! w" h
- }
$ w. }& p$ N' H' i) U1 f - #endregion
* }6 U8 P0 M: V. I" R' R - }# m E ~2 b5 Y
- else' p, Z% y) ^# E' \. I- x5 A8 @
- {
2 T+ H4 \, R( R - break;
2 Y5 U9 d& Q" O `2 M$ v. k+ i - }
1 J3 B( V9 |( K" k4 o6 C - }//while end
* Z) y+ V3 X* Y8 j- G. m+ | - }' v7 y A: V* C
- catch (Exception ex)" H- m. R) p' O, Q. Y
- {
. T5 H7 v! u( n4 B& j: \ - //整体异常处理) v) r9 a" j9 D! p9 p- P: Q
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);! _5 d4 _) n. B7 Z
- }
; e9 K- }- @9 z2 \) x9 s- X - }( g! V2 b, M* t% T: e# Z& |0 z+ l4 m
- 3 n- D. }, c% `) m
- : ~2 a4 b! _ c3 B) H
- public bool IsReusable6 P7 }1 `# D2 E4 q
- {; |8 @% {# s# M
- get
$ T1 v# d z$ P7 U - {6 p A; {4 J' H
- return false;
% t, d! I% c7 J# f+ q - }) @3 ~8 h& f- @' W8 S2 g3 T
- }
2 `' a/ S5 b% t - }. R) v u! ^8 ?4 @
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
/ h8 \' J! s0 k, X8 }- L) I |