|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 + q1 y' p# Y1 ? E
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;9 Q0 V( _5 ^1 h8 v7 ?
- using System.Collections.Generic;+ H9 q6 y- S+ e" Y8 z
- using System.Linq;
) t+ k" W9 Y) q& x7 X+ ?7 e - using System.Net.WebSockets;
2 b% X, y2 K( P7 R. m - using System.Text;2 ~" A3 Z. r! \6 l6 v
- using System.Threading;
; n) C. c6 o- n x3 d' C0 h - using System.Threading.Tasks;3 P0 |2 O; R* Y0 a9 m
- using System.Web;
, t) Z2 x8 m3 O( C - using System.Web.WebSockets;
7 @ v5 a/ H4 d5 E - " o& _. G5 A! u
- 6 i, ^- t5 R2 R& Z: G4 b: _
- namespace WebApplicationWebsocketHandler
+ ~8 f5 P3 ^* N - {2 u2 ], V+ a' `5 ]/ B
- /// <summary>4 Y4 X2 c2 A+ p$ d. _5 Y
- /// 离线消息- X9 q Z/ d! w6 `6 L+ `6 G% T6 f, X
- /// </summary>0 c" X; g* ^' P% t# @4 x
- public class MessageInfo
& B9 r K5 Z# D - {
$ H6 U# L7 z q1 Q2 A1 ^/ m. Y! m+ k - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
/ A, A; H6 B" Z) Q7 I1 { - {" \ g5 X# R& V: |3 q" `' R4 K& _5 w9 F$ [
- MsgTime = _MsgTime;+ P9 ^' t; F& c+ N; n, J9 {
- MsgContent = _MsgContent;! r: r5 M+ P) z
- }, v: b( Z5 S5 H$ T* W
- public DateTime MsgTime { get; set; }9 `# c Q% q7 a) b2 \8 e
- public ArraySegment<byte> MsgContent { get; set; }" d, {9 i$ V$ U) ~ ?
- }
2 k$ ~8 I' Y1 O! W: Q
: e+ Y8 |3 I# k; ?8 F4 C$ ~3 @ k
* M L8 W C3 ] s6 k; D- - }1 d: V* [7 G: J
- , i0 U' B& q8 [5 y6 b5 ? [' V
- /// <summary>9 \1 V r4 p/ q, N
- /// Handler1 的摘要说明
* U3 Q6 N! B2 @6 g; S% }# S+ o - /// </summary>
: ?8 Z6 p; V0 M1 `! c - public class Handler1 : IHttpHandler7 A# G, u2 ]6 N$ `6 c
- {
4 p0 C) v8 e( ~2 f1 D - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池' k" F5 ^8 k# R2 j
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
* j$ S5 f8 E) j, Q4 c - public void ProcessRequest(HttpContext context)( C; W& f' C; Y( h0 G [
- {
, N# y4 G; e* ]2 {+ s! ~ - //context.Response.ContentType = "text/plain";4 y. o0 u- Y/ y
- //context.Response.Write("Hello World");' {$ Q6 a' S q ?6 o4 e" O+ Z
- if (context.IsWebSocketRequest)
" e# G1 h7 V6 V; u* B - {6 E. m! h% C/ z8 E: g4 W5 E- D# H
- context.AcceptWebSocketRequest(ProcessChat);6 U$ w0 j, H" C1 ]5 E9 a j, }
- } 0 V. ?( O7 x$ {- W+ j* o9 e
- }
7 V1 A: g( K! [ - # r6 `3 S6 [) w$ A) C; T7 {" [2 ]
- private async Task ProcessChat(AspNetWebSocketContext context)& d" B2 o, b# T' U3 w; O' \7 Q1 i p
- {
0 }3 Q7 J3 D/ U; c& c% L, | - WebSocket socket = context.WebSocket;" V( x! U2 g! _
- string user = context.QueryString["user"].ToString();( [' Z6 v, Y; k/ Q, R+ D
- # D) s' m: e6 n3 N5 w
- try& {+ @1 K# }% ]4 M+ N
- {: x; A/ ^; Z, G/ e0 I
- #region 用户添加连接池
7 K5 i( H+ X5 |2 } - //第一次open时,添加到连接池中/ L- |# K A1 Y4 s9 }% R
- if (!CONNECT_POOL.ContainsKey(user))* t+ V5 t- L# I R7 b
- CONNECT_POOL.Add(user, socket);//不存在,添加
p, B0 w, u. R6 l8 W - else8 w$ A+ |1 J, }( f( z
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
) C/ s2 \6 \* V$ h; a; c - CONNECT_POOL[user] = socket;6 O# n! w1 |! C
- #endregion
, k8 ? i4 g* s# s! \ - ; j2 @& v u- K3 b6 a
- #region 离线消息处理. x- k" \4 y% h
- if (MESSAGE_POOL.ContainsKey(user))3 ~& C' \( w$ W) f( R
- {0 @$ N+ Q% {2 W. g* u
- List<MessageInfo> msgs = MESSAGE_POOL[user];
4 @6 }: f4 m7 w) v, \7 p8 Z8 D - foreach (MessageInfo item in msgs)
) T/ p& C/ C4 ~0 b - {
6 O. W* |( Q0 x - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);$ j7 b( b6 `5 e6 L5 W, C' w% ~
- }" \; k. R. ]! E0 J" h, A w$ ]5 N
- MESSAGE_POOL.Remove(user);//移除离线消息! q/ ]* Z A7 Y* \( {
- }5 d* q2 b" R( e! X6 @
- #endregion+ v; m% ]" t6 ?1 N- D
6 @& A/ l. S+ {! i6 w4 b- s9 N/ a- string descUser = string.Empty;//目的用户, P7 r) v9 Z) f7 S% [
- while (true)" d+ y) ~' e3 Q8 |( W$ Z+ g( y$ I, Z
- {
, {5 b# h/ J: u* j - if (socket.State == WebSocketState.Open)
9 I7 c; _7 H% g# ?6 `1 N4 m, c! \ - {
8 Y% j' P1 n$ Z k' v5 @9 H - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
/ n4 k1 Z1 A) ], s% N# c, k - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);& q$ x" @7 T- L9 g: `
- $ I8 I3 N' D' E9 W
- #region 消息处理(字符截取、消息转发)
! ]8 ~5 Y+ j; Z! a4 e8 M/ K' t - try$ l0 E. b4 ]# a8 F' e3 Y4 V b4 j
- {
: V) p: m1 b/ }" w - #region 关闭Socket处理,删除连接池
0 d% G1 E6 k1 F& P5 o- q8 J - if (socket.State != WebSocketState.Open)//连接关闭
( P# k' R9 h8 R8 J6 j% { - {
. m/ m/ J( k) R3 s - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
" q/ j3 X2 W) w j - break;
2 b* S# J' G* K% q3 C - }- K5 x Y- F! H+ T% D; h3 H! z! I+ F
- #endregion
$ s+ x- y- Z1 r# S* r6 h5 v - 2 A- k: B0 z, h# O
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息5 h& t& @2 H( K- P8 F6 Z W, ]0 N
- string[] msgList = userMsg.Split('|'); [: s! ~+ A9 H/ x% D4 w
- if (msgList.Length == 2)# S8 ~( T& R7 a: Q f1 {
- {
( H0 I6 @ |$ K$ [. \ | - if (msgList[0].Trim().Length > 0)
7 g" `: u. S" U - descUser = msgList[0].Trim();//记录消息目的用户% ~0 u$ e0 p Q& ^, s
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
9 }: y, L7 Y; }. v1 n5 {, [! Q9 H - }
& |: C6 z2 w' V# W4 K- ^ - else
) o5 m7 ?: J* e1 c7 F1 F - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
, ]& | y5 h) I9 F5 ?
' g) u+ d( `8 y! ?- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线: a% M: P i* j' G4 J. E
- {7 }2 @: q' Z) e1 W. b
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端8 B8 W4 X |0 }2 w% @9 b: O
- if (destSocket != null && destSocket.State == WebSocketState.Open)5 _5 X& R6 D0 ^
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);0 L8 o2 @ ?9 r& F7 \
- }
: J2 |7 m" ?3 ~: M4 i: E - else6 \" b# m6 K' k/ m# R- {
- {
/ P2 i3 _ s$ |& Q - Task.Run(() =>9 d0 ^& G, E/ u6 L0 Q
- {7 L3 a, p; |( Q) P$ U
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中) E4 I7 ]$ |+ }3 f( ^
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
6 U1 s2 |& q' s( \' F7 b - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
5 g/ _ g* s$ l: u1 G - });- f( S! T) N: S# K: m2 _
- }! z" f! ^% v6 ?
- }
! T1 A- Y, q: o+ N: ^0 h - catch (Exception exs). m: H, g( o* E, N1 W
- {6 `4 i" H/ b+ {. [
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息' b& c1 K/ j% X: n- N
- } ?9 V4 R4 h$ n6 u( W
- #endregion) n1 g8 t0 {" A& W, @: Z( T
- }( P8 ]7 m4 b8 s& Z8 U6 c$ A
- else
! n0 C. {5 L5 N - {
" Q6 D/ Q( G2 c9 ]9 g+ x A - break;
9 l. v2 `" V G+ w: Q6 J' {' q' n - }! }- {/ x! ]9 a2 X4 D5 A5 V8 G S) y
- }//while end
+ p5 A2 v$ X9 ~1 ~) n7 m* U% g+ ` - }% o8 i& G3 L" x- s9 M7 G, j
- catch (Exception ex)
" e0 _# e+ h; \3 ? - {( G4 z( B+ r/ I( z
- //整体异常处理) p X5 X! S9 z' [5 }
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);0 v/ F8 G$ t! b2 p# p0 g' I
- }
( M8 E E' s/ r! W4 i - }
- u8 G. B2 m# v% g
/ n3 k) I6 ?7 H- * |2 L' A5 C$ e: k, r$ m2 K! t
- public bool IsReusable
* R. ^* y: `( b' w0 | - {* q9 g3 d( x* h$ a6 A
- get
9 L# {. u: T H# D# x7 ] - {2 Z6 ~1 R* J- B
- return false;& } }! ?5 s/ f: Y8 y7 ]* s
- }; H! g9 W, @0 z! D9 L
- }
: y: H8 o8 P* ?! a( j$ Y - }
; E/ q$ p/ B4 ~7 N+ e; ] - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
- G4 k5 \7 {. K) W$ ` |