服务器端代码编写 1.新建一个ASP.net Web MVC5项目
+ }/ v& l* m- o9 ], _ ]2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
) Q3 \9 N# w5 V7 t9 b0 H - using System.Collections.Generic;- Z7 }: c! p Y8 N% h# Q% U
- using System.Linq;
8 z! ~0 F: d; V0 V" _" m" D6 f0 h - using System.Net.WebSockets;
1 v% b7 A3 M p! Z- ^ - using System.Text;
1 O+ n4 l& B, k& H7 |' m - using System.Threading;+ }6 s8 w3 f6 T, e
- using System.Threading.Tasks;
: z+ f# L4 X* N8 ], A( b, [ - using System.Web;$ l& a4 O2 D2 e4 k
- using System.Web.WebSockets;+ C; s& M& c$ p. P7 }5 Y
- 7 z! _ L8 ?6 l5 X9 [* V
H/ D5 p3 {8 d9 Z2 x- namespace WebApplicationWebsocketHandler0 ^; j! a# w' i; r. {$ e6 N
- {
( s, T! ~( g3 f5 M - /// <summary>% q* }0 h5 \* y$ w w' `
- /// 离线消息
s B# Y* g9 }5 w ~% [ - /// </summary> c' O, [. T- h: p. P
- public class MessageInfo3 |6 A1 a5 d5 ]3 m. b: y* ]
- {+ [: c4 p5 } Z5 ?; G% N
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)" t% \% {8 I- |/ y3 f# f9 J* E4 f2 ~4 [
- {4 N& |1 R* z2 R+ @" ^) b6 z
- MsgTime = _MsgTime;9 L8 o6 C3 l3 c5 }" l4 \
- MsgContent = _MsgContent;
6 s( N6 r7 y, U; ]; z$ h - }9 N4 N2 `0 z# e) x/ p! R
- public DateTime MsgTime { get; set; }- U9 `; ^9 y! m/ `" l# b$ e
- public ArraySegment<byte> MsgContent { get; set; }7 l d" Y" P* W" x
- }
: m. j" J- @ U/ z( w" J8 D
3 I" z) F3 b4 M+ S) G! t
( ] R+ F, {/ ~; G9 D; Y- W7 U, U% @9 J
9 M* M' W# G/ V: Z+ j7 ]9 [8 O+ G- /// <summary>
$ a2 j/ i5 v$ X) S* g. w - /// Handler1 的摘要说明
6 @0 K- {& T4 v) G6 f. z - /// </summary>
2 R* a9 f2 [ \3 w - public class Handler1 : IHttpHandler
$ {6 _# T1 `5 B2 h! E - {& K" C4 f# ?! P
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池$ y2 ^: E+ i, x3 d
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
% U. q8 t7 m( z - public void ProcessRequest(HttpContext context)0 _2 k$ p: { q) I S
- {- \, }& `& Z3 d: ?5 r# F9 [/ `
- //context.Response.ContentType = "text/plain";$ ^% j, i% X. k* F2 [
- //context.Response.Write("Hello World");! Y5 o) f' w0 q% j" V! `
- if (context.IsWebSocketRequest)+ e& s9 {$ R X& f h6 w8 f7 |7 b
- {
1 N9 G' ?& F: ] U7 I! Z" O - context.AcceptWebSocketRequest(ProcessChat);/ @& G" l1 f7 b; l6 y
- }
* f% W! d" N. F/ u - }+ T8 }* y$ F& h" H' ^+ j, {' i! L
3 z3 o; C1 |' m$ e! Z- private async Task ProcessChat(AspNetWebSocketContext context)
3 u& g% l* Z7 T3 d - {
+ s u0 j# R% z* S6 E% b' G/ L8 \ - WebSocket socket = context.WebSocket;; _ Y, J( A6 M' M7 Q
- string user = context.QueryString["user"].ToString();
; h& j9 A3 a9 q/ M% W( I; [0 q
+ R |# z7 K) n" V. ]7 ?2 ^- try
$ c) s @8 i3 v# a" T& u3 S - {6 C3 y7 B- J/ ]+ b* r- ]- _$ p
- #region 用户添加连接池
& i- C1 _. {3 H - //第一次open时,添加到连接池中
3 N( o, J# P5 F; S) Y8 O2 B - if (!CONNECT_POOL.ContainsKey(user))
" J' B; f, H; t) z7 T/ x, |7 v - CONNECT_POOL.Add(user, socket);//不存在,添加+ ~: `( {$ D1 T4 R% v* ?
- else! P' y! R( w0 n3 A0 n, j Y: Y
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新6 H T y' N! v/ _, G
- CONNECT_POOL[user] = socket;! ?, u+ ^* ?. @$ a, y" M9 h" [) o
- #endregion5 S& v, ~2 F7 M0 Y' x! b
, d. M4 M- R; o; K5 U- #region 离线消息处理3 C) `" S5 u4 X' v4 k* G
- if (MESSAGE_POOL.ContainsKey(user))% ]7 {9 r1 ?' r# ?9 H8 j5 e
- {2 c) D. [6 G, n1 `( `! u) Z
- List<MessageInfo> msgs = MESSAGE_POOL[user];0 j& L6 Y# W8 j% x8 @; ]1 g
- foreach (MessageInfo item in msgs)
. y7 \0 V" O# H8 ]3 W - {
* K' s' h$ ~: H6 W, p) l - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);2 R: q6 V7 m: J5 g7 T+ a. R* d
- }
! F$ W1 \. M, ~3 ]' @ - MESSAGE_POOL.Remove(user);//移除离线消息# h9 A3 |5 o- |7 |2 n
- }
?* S% _6 P7 k, M) c - #endregion/ e8 I( n; Q) A0 J
" t% D: a) B6 N! ]8 W( ]- string descUser = string.Empty;//目的用户# H! S6 Q& G6 u
- while (true)8 H N, b+ O( |2 h/ i
- {
7 T0 v# S3 j# Q% k/ D( c - if (socket.State == WebSocketState.Open)' b- k9 I, X6 y0 z5 b
- {1 H" ~6 r$ _: o$ \* W, y+ L3 {
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);0 c' N$ `$ b4 C
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);! `% l" Y: i2 F! g$ D# x
% |$ j3 s! ~( \1 m6 n/ s- #region 消息处理(字符截取、消息转发)+ o6 o9 p t) r5 @6 G% I0 }
- try
b, v/ z. k. s% L. t$ B6 W - {- ~: \6 T6 l5 J. Y9 Z$ c) N5 P# n
- #region 关闭Socket处理,删除连接池
% T, q0 }, U- |7 k) e1 s - if (socket.State != WebSocketState.Open)//连接关闭
" G: v, q; Q' q; g) w$ q P, C - {- V9 v- l& ^ B2 i
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池- ~' z$ R2 {" M3 |4 y8 R2 `
- break;, H& x3 O) O1 g9 @& I
- }$ h$ `# F" o, w Y" p) e# c* E( e
- #endregion( Y& F: q+ N( W, T j; u
% t+ z9 M6 j5 z1 ~ M& e- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息3 l0 O, a6 S9 u7 q! H6 |1 H
- string[] msgList = userMsg.Split('|');3 ^' ]+ z9 e: _: v s1 {
- if (msgList.Length == 2)2 R" h) l e6 r
- {6 c) f. l3 V& N* I
- if (msgList[0].Trim().Length > 0)
4 s0 r9 P1 W1 d+ u; h - descUser = msgList[0].Trim();//记录消息目的用户+ }- `8 a, A' E+ O) b5 @+ e8 B
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
+ ~" `1 U3 \ R2 I2 F - }
9 ]4 |" V# x, ]5 x9 F R - else
$ Z- l: h; s+ v6 n1 ]0 K: T' d. G - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
/ m, H6 }8 Y6 B- Y
) Q$ U0 x+ _& g2 w- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
9 Q. c3 ]' E- a; z: g# D: Q - {& g. Z/ E+ y7 Q
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端% {) L) R6 Q# E4 z1 Q [
- if (destSocket != null && destSocket.State == WebSocketState.Open)
4 T- ?6 M$ m- S# E5 w m9 c# ? - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);' }. I% |# B& k! B
- }7 V# J1 s& {# ~! N! G
- else) r6 F+ [8 c; @. |
- {
* @9 W& S0 @3 O) [1 l* _8 W1 Q7 k - Task.Run(() =>6 [1 H. z5 w) ?* v9 I5 f: _
- {
8 h9 G9 y3 v- ?) e - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
& M, Z4 w: V+ S/ D - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
1 V9 t2 r8 O& }1 M8 S: [+ _ - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息! g9 [+ K! z# k: X$ m( V
- });
; R# f2 k" G* f) C& z+ S - }
! P) P. \0 \# |7 ^ - }
+ T/ i) c8 {1 f: n) n - catch (Exception exs)2 U9 {+ D/ f! d8 k2 i
- {
; _3 A3 C/ l D' C6 Y# g - //消息转发异常处理,本次消息忽略 继续监听接下来的消息4 M, e; Y y, K, i9 P3 K, Y$ E) f
- }) d: o/ }" u9 a& \1 C
- #endregion# h% l0 y8 e) a7 L3 r) R
- }, H+ m8 N2 e& P
- else* d) Q) q6 ~4 n$ @) ^1 r
- {
+ u- b$ w t# P3 k/ A - break;- y9 [5 {8 B S3 Z
- }
" Y" i6 h, k) t5 K' P - }//while end
4 o/ X' E9 _7 f) W8 q7 c - }* v3 \, U6 `4 k1 \1 I# _ k
- catch (Exception ex)1 g5 v- U* I' _+ q; e6 h( A
- {+ ^5 G: h6 g! i: \* w+ e
- //整体异常处理2 Z+ d/ i% N+ U5 f, ]; E0 Z+ |. J
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);; N) S t) I# v6 Y) _# P; f
- }
, b& F+ K& `; Y/ p - }6 E5 a1 q0 Z+ K, X) `
' p$ b8 o* I- w. D- 5 }% J/ ^" T8 p( s0 T5 q
- public bool IsReusable
5 \7 M! L) W u7 R# k: O P9 \ - {5 k) [* E: Y" j; E
- get
$ E0 u1 p6 r. R$ {# |# B - {
' A: C1 y7 R6 k6 {& S1 I - return false;2 q9 c; }5 O& d% j# B
- }1 G. V+ k( r l9 x5 d, @; u
- }; q. c i5 q0 [) p% Y* I
- }* K8 P6 H& k; N! C
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 3 `/ @1 U. s: c" h' O0 i) K
|