服务器端代码编写 1.新建一个ASP.net Web MVC5项目 + D3 f. v* a" V
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;! {) ~! U8 d9 I5 ~2 u
- using System.Collections.Generic;" L" T. _9 A$ T( i6 r5 }5 m5 p
- using System.Linq;
/ t; | c+ M) ] - using System.Net.WebSockets;9 y" Q" i5 F2 J0 Z8 m
- using System.Text;
- L. o8 P3 n$ X% R H6 d7 v: f - using System.Threading;( K0 d3 s9 M" o, M% r
- using System.Threading.Tasks;3 P& l& W0 y. h+ a
- using System.Web;, ^: W5 `9 d; B. l0 f0 k+ q: y
- using System.Web.WebSockets;
% m* V& d0 ?9 ?2 o+ U0 \5 z; O - + e4 {9 ]: W+ W) `, O: r
' Y4 X; ]5 H( d6 x# U) a- namespace WebApplicationWebsocketHandler
" _. C8 G% i5 @ - {
2 _" e) [4 [3 H - /// <summary>
. j% m+ U. g3 i, u! K! O& a2 g - /// 离线消息
% c' V# l; o9 Y8 j" Y4 J( o* D* H+ B - /// </summary>
) N: x: T! c3 B& Z; i" j9 Q" W - public class MessageInfo% `" Y1 T0 A5 ]+ j4 J. q
- {7 T, z9 R) Z" i) Y! B
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)* M4 n. q( Z0 t
- {# {5 r- V- s) R% {
- MsgTime = _MsgTime;
N* a9 w& r- {- z - MsgContent = _MsgContent;/ J4 P* R7 _, |: K, t$ u: H
- }: d0 r. V& P3 P+ u
- public DateTime MsgTime { get; set; }) l) B! p t2 q6 f! D% m; l
- public ArraySegment<byte> MsgContent { get; set; }. t* A; T0 n; |3 u
- }
# K: h8 v1 ?* K2 n9 C6 V - 5 c2 {, `! D$ T7 {+ R' r2 T8 C8 H
# M; Q* K% O6 |& R! W- n6 @( e6 ^% S3 }3 U) ?$ G4 D
- + a1 ?& q4 |$ x7 [9 V
- /// <summary>2 c$ i) i$ T4 L9 P
- /// Handler1 的摘要说明
) k3 Z5 C8 Y7 h0 Z - /// </summary>$ b; W' q" { S$ {4 \& x$ l( o
- public class Handler1 : IHttpHandler
3 Z/ U) K; B& ?: Q! `( _ - {
- ?. q8 _. i! X7 g - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
! H2 }( V, U* T& @ - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池8 Q0 b7 R1 m+ N3 S; e% F
- public void ProcessRequest(HttpContext context)
- E! v5 u' U3 a, [ - {) T& j& y. ?$ k9 E5 `
- //context.Response.ContentType = "text/plain";: J0 a4 A! ?4 G
- //context.Response.Write("Hello World");
2 t% b" i) j" Q- b - if (context.IsWebSocketRequest)
- r* v @5 L& X) x# w - {
% `( v' d! n" Q9 R& f/ s - context.AcceptWebSocketRequest(ProcessChat);
t7 u3 K( O% i X# j - } 1 |- Q# ]# v2 m8 Y0 z( C+ ]# }
- }
* Q( U( A3 w: ?* ]7 J
0 `& B3 g3 J1 h. i& B% Q- private async Task ProcessChat(AspNetWebSocketContext context)! E0 I. ^6 E5 q$ Z$ @- i
- {2 d- o4 i; z2 s+ B" [* O
- WebSocket socket = context.WebSocket;
: d/ @3 Y- f+ p, c9 y" {, i8 Q - string user = context.QueryString["user"].ToString();
* @' M' B% h A* Z. p5 B
5 b9 R0 B7 X/ H2 G9 Q j- try
! U. X! Y4 }4 J2 T - {( e% X' f3 p3 `% [" o
- #region 用户添加连接池, d- V# R2 x( U
- //第一次open时,添加到连接池中
7 G* R* D% ]3 B; z+ Z% _ - if (!CONNECT_POOL.ContainsKey(user))- e' Z2 k% t4 z. d$ w2 E
- CONNECT_POOL.Add(user, socket);//不存在,添加 x% Q! D e& X+ d2 w( e
- else' W9 B" C0 ^) V8 T# q3 I- n$ _2 g
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新2 Z) S( R4 ?4 Q! G
- CONNECT_POOL[user] = socket;
1 m( x5 p8 Y: z1 t" W6 S" g; s# h - #endregion
4 i: Y- e# ~0 l% N- W) t - ; E& Y9 S' W P3 m* B
- #region 离线消息处理
: P8 n" z2 I; _% Q8 c - if (MESSAGE_POOL.ContainsKey(user))
2 a7 @4 S+ Q+ H7 S/ x - {
, ~6 _. V# L9 Z - List<MessageInfo> msgs = MESSAGE_POOL[user];2 u! x' \% l7 u5 G9 d$ n
- foreach (MessageInfo item in msgs)
! j" m* p$ K2 L - {" Z6 a* }; [+ u/ c& F. ^
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);1 v, }# Q" i2 f* u3 x9 V
- }
: B4 A* \, i0 G1 g% y - MESSAGE_POOL.Remove(user);//移除离线消息' ^4 S1 i" S. s, B( z
- }7 t( c' k: f$ m4 o
- #endregion
+ s! y% k6 P. W" x Z" j! t7 D - , G6 l0 |6 H. @5 ?% }3 w
- string descUser = string.Empty;//目的用户
- W' a: l6 i$ e$ L: S! g - while (true)
: m" |/ S7 s6 O2 N/ C4 \ - {; w6 O3 B$ l# _
- if (socket.State == WebSocketState.Open)
+ C& S N5 z: ~) d; l - {( r, n, |1 m* I9 T! f
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);6 n, R @3 [0 T% X* U( s4 P+ F$ ?
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);6 J7 L2 L8 K+ n+ g+ e$ B
6 j9 q: U9 f8 b F; X! b- #region 消息处理(字符截取、消息转发)
. W# `6 g9 A2 z0 w - try0 t3 y5 X. y1 a y1 Q% ]
- {1 c7 _; I; o( p
- #region 关闭Socket处理,删除连接池
7 [* X' x1 X3 A5 ~6 X! U) u. M - if (socket.State != WebSocketState.Open)//连接关闭
0 {) p4 K5 X Q! w - {
. T! I3 Y" j _# ] ^ - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池8 X# B1 c( f" Q) E" c Q# ]) F% ?
- break;& s3 A1 t. I6 u* B
- }/ ~( V G7 Z* ~) H% j
- #endregion
, T1 x/ c l3 w* i d, u6 j0 L - 9 L3 o. Z, _2 z6 d+ n4 s$ o; z
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
. t& z! o, L2 T5 x - string[] msgList = userMsg.Split('|');* y8 z0 P9 O2 c+ j5 V, V5 P
- if (msgList.Length == 2)
7 A( g- y" k8 H9 N8 ?3 f - {& Y! u7 }0 ~: S$ B/ E* E' j
- if (msgList[0].Trim().Length > 0)
" D8 S. c( \/ O) ?" s3 E; J - descUser = msgList[0].Trim();//记录消息目的用户6 B+ d8 E! S c/ U! n
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
$ O# i. h9 [( O" l o( [ - }5 P' B }4 T6 m3 u3 r
- else- P: Q$ @- {7 k% o5 F/ [
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));* W1 k# i/ ]' l' k M; `
- : C8 \, P3 D! M$ n d3 \6 l( d
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
. w/ Y5 c) J+ O - {
0 w* Q4 y! i2 O' X6 i. I - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
: `8 z5 Y0 \: M, r - if (destSocket != null && destSocket.State == WebSocketState.Open)
) W! b2 i7 s8 X* S - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
$ T# U3 E5 `' ?& a$ l S - }
' B9 C. W* n' ?) Y4 n0 @ - else
; ]' S$ C# t4 W3 V. j9 u4 B% f - {
5 }' u3 P5 p2 O2 Q& Y2 g, H8 v - Task.Run(() =>
, a J$ b0 c1 C, i" Z/ [ - {
5 p. |0 p! t# l - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
1 C. \, b' }- O2 ^( N |, m - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());! y/ m7 f: j& O; _- @, V- W
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息6 @0 \# a" Y) J8 E" f$ F
- });
8 S2 D2 @" r# }2 G+ f1 c/ L - }
; O) [1 h1 M! m; v; X - }0 F2 u# g. `" F
- catch (Exception exs). D# e# H3 _9 s. G: N
- {2 f; K9 b" ^; \3 }4 y4 C& \# n
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息+ S. m# o! }+ d& o! q% [, V$ y
- }
0 e* L$ U3 _1 N. c" \! y - #endregion
& A- g+ j+ k0 Y6 F, O$ U4 T - }
0 W; X1 P9 T4 @/ d; N6 } - else
% R% q3 i9 G" c1 |0 _ - {% D+ `5 X. N9 X4 l% \. {( M
- break;+ x& }% P/ G& Y; }" ]
- }
, P) H& A3 L! R* `1 H) h - }//while end; g6 v3 G+ e0 H/ S
- }
2 v' z4 m& ]9 q3 Q - catch (Exception ex)5 e+ j' g0 B7 u5 o
- {/ z' x+ _! w) q: b( p2 |
- //整体异常处理
" c2 N) F7 \4 K3 K5 U - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);: B1 F7 a3 ?: a! s; o/ i
- }
5 k9 o: f& G7 t5 |2 q - }
Z' K5 m0 e$ Y; T9 t( @! W - / T& I& Y1 ^2 m" |
) X t/ U, H. F( ]* R$ L& I7 @- public bool IsReusable
4 `% ?* a ?7 N0 B. v9 F; I$ ? - {) @3 q( }! f' |% S
- get' Q) T; b4 P, o4 h8 X& A
- {4 ?/ U9 F# g7 m8 E& ] j
- return false;( ^! ~5 r$ q4 V% Y4 G
- }* Q2 {5 n% w5 W
- }
3 x2 b* I2 H% g) g0 L+ K - }- P) s, Z3 @& A( }% [ @2 E+ s4 F, y
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
% S: G$ A4 Y: u" T( T, h |