服务器端代码编写 1.新建一个ASP.net Web MVC5项目 : G/ o; e2 l' n' _ t0 ?, V9 o
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
3 c& S3 c" K$ i. T) f - using System.Collections.Generic;
; Q# F- s$ I) V6 W' Y - using System.Linq;/ d1 \& U6 R: r+ i
- using System.Net.WebSockets;
% M, H" G( J0 h5 ? - using System.Text;- g0 {( t4 X8 I; H3 F7 c
- using System.Threading;# q2 D' @' h5 j+ t( j0 G) _
- using System.Threading.Tasks;
# b l5 c$ r) ~6 `& k - using System.Web;
+ l' n: f" Z0 i& v+ M6 A - using System.Web.WebSockets;
0 b8 S4 M$ C( \% P3 m - ; H) g# C! X. P+ O
# y. C& i' {4 z- namespace WebApplicationWebsocketHandler$ S0 I2 L+ H! x/ F3 z
- {
# h% O1 b4 j0 j - /// <summary>7 h* T) r: M3 o4 A. o" n1 [6 y
- /// 离线消息
' R; [2 K( d! r - /// </summary>
8 B1 Y" j5 b, B2 u- S - public class MessageInfo
+ \7 w. u7 L( c5 c$ D5 X - {& L* H( A4 R2 M/ B$ M
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
4 J; C: C N' \. t4 B# ? - {
% {8 L6 t: S% @: {5 n# _ - MsgTime = _MsgTime;
V, x: h- U b; X" K: L - MsgContent = _MsgContent;
, p4 ~, r2 T; t! ~ - }
) F! S* r7 V0 `* c5 N2 }0 C - public DateTime MsgTime { get; set; }3 G( B/ a- ~# T
- public ArraySegment<byte> MsgContent { get; set; }; P+ A D8 V% g- m
- }
0 A( B5 x/ L# z& G' h
) U* V$ [/ H# \: w/ \/ V- . V* p7 C% K, {! C% Q( { f
- % y" Y7 W# k- u+ {
' G1 I I+ q" W7 }# `# d# @$ a' w- /// <summary>* Z/ s8 ?! U0 w. L9 i
- /// Handler1 的摘要说明
. C3 H0 I7 Z7 Z' v. g4 ` - /// </summary>+ w8 s; s' J; h. N9 Q! P
- public class Handler1 : IHttpHandler3 G) s1 E% i0 k2 i, n5 j
- {8 J8 ]! o X5 T4 ]) N) ^" V' _: F
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
! o3 c% t+ e' a U - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
( W5 N; a6 {7 e# s" E5 ?2 \ - public void ProcessRequest(HttpContext context)
/ v$ e! j- D. ~ - {
: I7 F; x# E2 e4 k2 X9 t @3 ] - //context.Response.ContentType = "text/plain";8 h$ H, Z7 X' W9 ~! E
- //context.Response.Write("Hello World");+ D% u D' Q2 S& E( i
- if (context.IsWebSocketRequest)) T1 x8 w% k% N* ?
- {% H) ~$ c# ], D/ N
- context.AcceptWebSocketRequest(ProcessChat);
: r, v7 W b3 U3 D3 w% O8 S, } - }
2 n) P% c6 ~: e* q; y! d+ Z' k - }
' n! R `4 D' g5 {# F: u
" V# p+ w- O {- private async Task ProcessChat(AspNetWebSocketContext context)
/ u/ D0 I+ z$ i/ f$ }7 s1 P ~ - {
5 g. I. I* P" r7 _) U5 e. t2 [0 @ - WebSocket socket = context.WebSocket;
9 e7 @# b* P; D) G0 b V - string user = context.QueryString["user"].ToString(); r4 R7 z) _0 W& G- O8 e
- & ?8 L0 [( ?$ h
- try
& v9 b/ q: {1 `# Y/ f& L3 z - {
. \' w8 ?! w% R6 r' c - #region 用户添加连接池
6 i# q+ _! b. R' R% f - //第一次open时,添加到连接池中/ q' B) Y# r& R- e
- if (!CONNECT_POOL.ContainsKey(user))
2 y8 Z: s; `! J, g - CONNECT_POOL.Add(user, socket);//不存在,添加3 c: O8 U- ~+ n, \$ A8 `* U/ W
- else: O1 Q0 a( Y9 @& n# ^+ z/ {
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
/ [# a. l! X( ~: p - CONNECT_POOL[user] = socket;
' a0 D- c7 }; t4 }6 h - #endregion
t7 ~# X- r8 ?7 k+ I9 V+ n. _ - " Q" H W* }: r0 W( W% u# e
- #region 离线消息处理
3 q$ X5 h( P5 N% w - if (MESSAGE_POOL.ContainsKey(user))
3 ?( Q9 w& s5 f" K1 f - {
/ q9 m7 P9 y2 P) s" w5 p. @( \ - List<MessageInfo> msgs = MESSAGE_POOL[user];
. M7 Y, ~! D% o+ v1 U" @, c - foreach (MessageInfo item in msgs)
1 d) T. P3 L7 ?1 n/ k' F7 ?- b' r" S - {# ]" x7 f+ G: u& c( u3 @% {
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);0 @6 G/ W" G' \! p. t5 P- c; e2 F
- }
4 o: P* C( T" Z - MESSAGE_POOL.Remove(user);//移除离线消息! s# @) h9 H A0 @ E4 }
- }
2 A! o. }* f5 J2 q0 M - #endregion2 L$ p' c$ s; h$ ~3 Z
8 f4 b/ Z' p3 \% ] i& ~; s" i5 ^4 ?2 [- string descUser = string.Empty;//目的用户
( d( Q7 @$ ~& s: V - while (true)1 ^# ]8 }/ X, S) W6 N0 O8 N
- {5 e# a" w9 Q: O
- if (socket.State == WebSocketState.Open)
1 S) R6 o5 s' P) I J8 @ - {
; o2 x9 P- h( i% n - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);! K1 \, ^% r. G0 |
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);' w9 {/ p. g0 y. M0 `5 k
- - r) u8 _5 Q3 |- E
- #region 消息处理(字符截取、消息转发)! p S$ U9 c# _* ~
- try1 Z& o3 m+ ^9 `# B' E/ V
- {+ |, \1 N4 Z/ i! |' m9 @
- #region 关闭Socket处理,删除连接池3 Z/ ?- F% \+ U$ n
- if (socket.State != WebSocketState.Open)//连接关闭6 n2 |5 ] K K& M* H- G
- {
2 Y- D6 q: X$ G9 p0 q3 `7 {2 u3 G - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池/ ^7 \, {" b2 v* R; l' E ]- f
- break;
5 c/ u" |$ i- B. r2 q: g/ f- z - }# k( Q- y8 z- p9 d9 R& p) k& J
- #endregion5 T8 w0 L7 L: H D
% c4 L5 h8 Q1 F; X" q- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息+ c1 q1 x2 G, N- Q
- string[] msgList = userMsg.Split('|');
; e' y3 V( V8 t8 k - if (msgList.Length == 2)
8 [& u0 n* l( }; G, j) { - {. c: u! t) p+ Y/ g+ x
- if (msgList[0].Trim().Length > 0)
# X; O/ k/ R7 R9 S) e4 i - descUser = msgList[0].Trim();//记录消息目的用户! I6 g* q, M4 Q) j" h6 S
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
- ~+ j. M; f. g. ?; l - }, Q6 W7 C$ ~$ N6 @( a4 \( K
- else
$ I9 _# q* M$ u7 a - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
! e: \& x1 {' P, l7 d+ R# c$ I9 v
1 q7 I& S+ d) \# S& Q- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
8 m1 W' |& _' z: u/ e! t - {
1 I! R3 K1 Z% B1 r% K! T* W - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端/ S" m$ E4 _3 X
- if (destSocket != null && destSocket.State == WebSocketState.Open)
9 P% s# D# N+ l6 `0 Y - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);( _& \+ H! Q( Q; E+ P1 s7 w
- }+ n: h x* L" Y
- else
/ P* e' T+ @0 g3 n - {
5 z" g, v8 ]7 p: c* ], z - Task.Run(() =>: y3 Z" P3 y$ }8 Y& @' |6 o* i
- {
7 y. M4 q! k9 L) ~) w/ q9 k - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中 j7 b5 l5 X; |' p, X: m
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());, l# n7 L) b! w0 P) {9 O. Z
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息, r! n+ B {/ M3 U
- });
3 @6 v. ^9 U: J - }
2 c/ X/ {2 m, ?' G1 c - }7 z; F8 p* E$ p5 ?! X: Z
- catch (Exception exs)( U6 g$ F8 S0 D' Q
- {
0 \, a# H9 w4 s( x1 M - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
4 L1 v& D% J) d1 Z& D( P# Q - }
8 @& S) W5 X6 o% M8 j$ d5 m - #endregion- t! J# `. G% ~& D# ?
- }
k, v$ P) t0 t+ o/ T: Y - else( D5 q8 F0 J; |" K& ~) q4 h
- {8 W& f: m$ l" G* H$ ]# l: \
- break;
$ e+ G% U3 T+ z2 s - }
" h. V7 h5 @0 {1 B8 ]/ R - }//while end
# E+ H/ p" U6 e" U- g3 _ - }
" f+ c& K( w& \. k& d8 \2 ~ - catch (Exception ex)
1 y$ H ~2 h" z3 f0 ^) P - {
, p4 Q' t6 ?* _. n% W - //整体异常处理! W& v) }$ g$ `& k$ J) r
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);' R4 M9 x( l/ V; ?# L
- }$ L$ |( F! x% G9 x& s& l3 I
- }
" ~5 B5 W# @ l2 j; p+ }
! ?5 c- W7 X' D
, w0 f: |- m J+ s6 Y, B0 M$ v- public bool IsReusable
2 A, z: U+ i/ Y1 A9 U9 q( b - {/ L8 h* K; a. T' S0 Z' m
- get
+ o! l1 A4 V/ ^4 ~4 [( m; a! k - {
: O# y6 {" o' A* w; B8 H) | - return false;' O5 {# R0 O) R Q7 v, C5 S
- }
& f$ O& q* E+ k% t% y; ~ - }/ G' F5 R) t; |! M$ i
- }+ b$ ?6 B) [7 S. f6 O6 A
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
) N) k3 ]% u% M/ |5 e |