|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目
' w0 G7 f+ H! R0 @+ M2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;4 x+ D( ?3 @, P
- using System.Collections.Generic;
1 p6 L2 Q2 Z; V - using System.Linq;
! x7 J9 b0 H0 ~- A7 v9 L5 b - using System.Net.WebSockets;5 i& b3 s- w$ u: \, ~
- using System.Text;
; O8 H2 U# x6 w0 ` - using System.Threading;
+ ? a: K& k% B& k2 b/ G - using System.Threading.Tasks; d: m# Q& H9 o" M
- using System.Web;" d, U& W9 L" ~
- using System.Web.WebSockets;" y" Y, E2 K# F
- - d3 h; f/ T3 c) T; f/ p$ G
; E' Q, `# j# R9 m# ?$ ^* E* s- namespace WebApplicationWebsocketHandler
+ r. `" a o* } - {
+ O7 V( I- S/ I7 i/ G u& u1 F6 [8 ^ - /// <summary>
! Z! @7 C7 Z8 {- ] - /// 离线消息5 K, F8 M% ?8 Y; F6 o% Y6 k
- /// </summary>2 u6 q! o4 i6 w! s5 @6 M
- public class MessageInfo
7 X- j: e% |/ Z - {
/ d3 {5 a' m% n0 |$ W+ z - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)# |9 [; m# V/ N) c7 A
- {
7 x0 K3 S/ W- i8 A# M4 q- e - MsgTime = _MsgTime;
3 R- _5 S+ x7 m - MsgContent = _MsgContent;
( F. o& @6 F- _- W5 [; ^ - }
5 u4 Y# c4 ]+ d$ |' H - public DateTime MsgTime { get; set; }, F8 U# H8 W( O* a# u \3 j" \/ c
- public ArraySegment<byte> MsgContent { get; set; }
( Q$ k m: w- m, \- { - }
4 u/ t* B {) S& G+ v2 \ - * Z9 B5 A3 W+ q
! S3 D* e4 O& N4 T# B) i
$ T7 P7 N) E# g- j( g- 5 y) P* G6 D* x( q6 d
- /// <summary>
* | g$ l! _9 q* ~' [" \ - /// Handler1 的摘要说明$ I6 Z! }3 b7 _
- /// </summary>
' x0 F& J8 [* L5 I. n - public class Handler1 : IHttpHandler
; x+ S/ a! N. @) e" S1 r6 R( j - {" o5 L$ J/ q# ^/ Y( r
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
1 g5 e& W: U1 ] - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池' N2 ?3 W& W5 V
- public void ProcessRequest(HttpContext context)( ~+ }7 G3 m. |3 c: Q% Z! @7 s" {
- {, }0 W7 p% R4 X: U) J
- //context.Response.ContentType = "text/plain";' s* W5 b* K. G* Z9 t
- //context.Response.Write("Hello World");
0 |( H/ d7 C7 s! \ - if (context.IsWebSocketRequest)
4 Y. g" g) W Z @2 d5 l - {
" f% i% e; U4 S! ^# e! z - context.AcceptWebSocketRequest(ProcessChat);
- Z2 w9 a, Q0 ?9 Q: ^: @& M - } " {; `' Q6 h* m- G2 h$ \: p) w
- }
4 y' L$ j1 F. y1 t' ^! P) n - $ ~" P1 w3 b: N+ F v
- private async Task ProcessChat(AspNetWebSocketContext context); n, h$ R: u4 U- o- S% \9 d& ]
- {
6 q7 L5 |- N0 T( n - WebSocket socket = context.WebSocket;3 Y' ^. r% q- I1 Q5 q5 u
- string user = context.QueryString["user"].ToString();8 o6 ]" ]- H0 F+ J. A
- 8 B& O, @, B) d
- try
9 H, W1 ^& M1 @% W* V( b - {# L0 m7 E$ Q* {
- #region 用户添加连接池$ J3 f% S, N) S9 V% `% A. \; F) D" [
- //第一次open时,添加到连接池中* c0 z, j9 i1 P5 y; v1 u0 p/ c
- if (!CONNECT_POOL.ContainsKey(user))
* ^0 ]$ g) H9 ` - CONNECT_POOL.Add(user, socket);//不存在,添加
' ? {# T# L% q( P/ \ Y& k- R5 x - else
) j1 A9 [" }* U9 P' h% y# f - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
7 }8 `5 E) c+ q - CONNECT_POOL[user] = socket;4 T" w' E( X/ c
- #endregion% }' v, L( u4 B! z, i/ y5 U9 X
- ' {$ D0 t1 ~1 D( E
- #region 离线消息处理# `- d' x5 e3 Z
- if (MESSAGE_POOL.ContainsKey(user))1 `! o2 t& e) n, d: Q; R( @- N
- {" G" L8 ^% b1 a3 N0 U0 N) `
- List<MessageInfo> msgs = MESSAGE_POOL[user];
# ^. L d4 S3 ^! s; p - foreach (MessageInfo item in msgs)+ D" t# L" s/ n" Z) t
- {
8 `( d/ C1 ] O2 o4 i& o - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);* B* M2 O9 `9 u6 ]3 Q+ L
- }
+ G/ }" }2 O$ P- a$ }4 | - MESSAGE_POOL.Remove(user);//移除离线消息% E- l7 m+ \7 U# r2 V/ {1 @' [( P
- }( T3 m2 [! m4 Z" r
- #endregion
( T: L" l$ I2 X
4 T- Y7 W) V/ \* l! ~" H- string descUser = string.Empty;//目的用户1 r, Z& b$ p8 y. X# J' F
- while (true)' W, l3 s7 [0 y7 _- o3 J/ B+ C
- {1 y( k. [9 V4 L$ O% R: \- l) _
- if (socket.State == WebSocketState.Open)
! X4 h U$ P \% j" a' \/ v4 k i - {
9 r* A2 W/ D6 w+ n) Y6 E( }3 p6 t - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
2 b. s2 G6 R' Y6 Q - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
" L0 n0 i, z7 a3 b7 v1 }, {2 y
/ D% `* Y3 B) W% _9 J7 d( O. o" p1 L- #region 消息处理(字符截取、消息转发)/ g& S2 A1 t0 Q" |5 R" Q! A! {/ H
- try' [' u! J- u* f. z% b# i3 g
- {
k- d- Q5 I" C6 i - #region 关闭Socket处理,删除连接池% Y% `" [) @ l7 o9 P
- if (socket.State != WebSocketState.Open)//连接关闭" N8 d9 P8 [3 b/ i# _
- {7 x( T+ L8 [6 h+ e2 _* D5 I r
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
8 l& ]! u$ p2 N# \) s6 g# K - break; |1 h, G0 k5 |
- }* d" z2 a: `8 I
- #endregion( R) V* [) R- _7 O
- + k5 q9 g; k0 x3 R# a: G$ D; V% T
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息6 p4 ^ o9 [! K' V3 b. T1 ^
- string[] msgList = userMsg.Split('|');
9 p* u8 D+ w. d# a1 a7 C2 V - if (msgList.Length == 2)
4 B+ E, N* u8 R g5 Y8 W - {' h3 f& t& q S5 {, x: n! Y
- if (msgList[0].Trim().Length > 0)
/ W# {" ^! F7 j$ J9 X( P - descUser = msgList[0].Trim();//记录消息目的用户$ J2 U3 ?3 |; c, y1 k
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
0 Q* H( O& q( l g: K1 h& q; R - }
3 k$ ^2 w0 m/ s! q' N' p - else
( P, k7 U8 S) B; M, Q - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));# E8 Z4 ^5 ?; M1 R+ K
- 2 M) E4 H8 Y) O
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线$ _* L( o1 N: ^) ]* r/ J7 ]
- {
+ X- `0 g1 Z) j2 R - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端& X5 _: z0 `. P
- if (destSocket != null && destSocket.State == WebSocketState.Open)9 T5 U( G0 l, z6 k S2 v
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
. C& D# ~8 ?* H% x* e1 J - }
, [+ `' V7 O# t7 [ f - else: [- U. x1 l% Y! \2 G
- {
9 J. \( s. d) O2 G/ j3 M# P3 V: W0 D3 Q - Task.Run(() =>
! }$ i; b7 D! W - {* x+ L8 d) ^# P2 U, y$ L
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中$ H. o' P5 W/ f- d
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
4 T) S2 J; q) g1 E5 b% K% ` - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
$ K. B- u- B2 h' X' b& C& e( f g - });( B- H1 _9 B. t2 Y- s- r
- }
" p' z o) P9 E3 j0 H$ K - }
* f- m& [; `1 b2 i0 n2 V - catch (Exception exs)+ a5 p! |6 w- ?8 _
- {9 C4 e( D5 u* v |: _3 S
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息. W. f# r- l6 n$ i% P" |
- }
& O7 h- c7 i$ W4 G8 K8 e - #endregion' D7 c) U- u, u
- }
3 ^$ O6 U; @* t# H - else0 J. k2 D4 Q: [6 C4 M% K; M; ~
- {
! p- d) a/ |9 K& ^2 T - break;; _# F5 @( ^' n% h2 V
- }
( o4 X. Y' @1 H8 X) f! y6 E - }//while end+ P4 R. z N0 g1 A: p
- }) X1 h) D* G$ m+ X
- catch (Exception ex)
3 ^6 v/ L% B0 R" D8 T8 W - {
! g6 u" h; Y! r! M- ~* U9 N( r - //整体异常处理 }( | E, P/ H7 F' y
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
8 u# L# O) p Z- u0 F2 Q - }! E7 v J$ w _6 W2 a' n
- }: b; X( f# u9 A+ [# j' r& H
% p) u; T) {, `! o- 1 O% }7 Q1 f+ s: Y
- public bool IsReusable
* Z5 x8 Z3 H7 v0 _* ? - {
% l5 Y# {/ d0 c; V0 c, i - get7 W1 k6 A0 h: Z. K
- {
2 q' u8 i- G& @9 M& F9 @3 r - return false;
" z* s* b4 ] D3 Y$ _$ P9 [* M - }
: b/ H' m3 ]3 ^" Z - }
4 A/ i; I, ?. W( N! T) `" ? - }' d5 j% `% { v4 }$ c% l0 p3 h0 Y* _
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
' O. W! ^8 x* C( J J0 n& h |