服务器端代码编写 1.新建一个ASP.net Web MVC5项目
5 a- E2 b* k, J, S2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
' Z! l% B, ?% I$ s- h1 q - using System.Collections.Generic;9 N7 M# R. R2 s! N6 E
- using System.Linq;
( d5 J, b% ?- A - using System.Net.WebSockets;
' S$ z. a# M9 U! \: @) n - using System.Text;7 @! M0 T5 G% K* F4 N
- using System.Threading;5 Z7 D4 z' R3 t. ?
- using System.Threading.Tasks;
- P0 M& c+ n A% K/ l4 L - using System.Web;
, p# T7 Y* g. }, I1 }$ H8 X3 {) ` - using System.Web.WebSockets; Y' |6 l+ C" c6 @) y! ~. i! F
5 O5 x7 T$ G4 z0 r. S- C6 z3 M- k! {! y" N& j, J# c3 s0 ^; i
- namespace WebApplicationWebsocketHandler
& t; b) z/ @; l7 _9 @7 ] } - {
+ m$ n7 o8 P6 Y4 h D - /// <summary>
( N% j; ~& F+ h$ k6 j - /// 离线消息
- D5 k: T( X5 L/ V& ~9 c - /// </summary>6 ~7 r9 s6 l1 |; A
- public class MessageInfo: Y4 `# u9 n* k+ z* Y& O& G
- {
" ]( H$ b b; L6 } - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
4 O/ o9 _+ B9 u9 {& F8 P7 O - {
1 Q# A' i( l# e$ C0 s5 W - MsgTime = _MsgTime;: N8 x/ _6 y4 k$ Z: v) u% H: g
- MsgContent = _MsgContent;$ L" h/ ~$ r! ^0 L9 t$ o1 C+ h
- }
4 E7 c b5 n, I `7 p) Q - public DateTime MsgTime { get; set; }
% k. e' F1 p8 [& ]. L( {8 b; ?7 y - public ArraySegment<byte> MsgContent { get; set; }
- W& t* Q& ?- J3 |: b' K - }
2 w0 d4 [; m- N9 m' a! K7 | - $ I1 \5 B0 w- }
- 4 ~7 e; f) h% s- a& Q
- " X' f6 }! |- ^" W' U3 f/ _/ O, g, f
- O$ f5 {0 s) p2 L' f4 M6 F# H) F
- /// <summary>
2 A( g' \! O- p4 A" W H( j - /// Handler1 的摘要说明
+ R- G0 |- z9 H' i$ q z) p - /// </summary>
3 R# I$ P2 B6 T - public class Handler1 : IHttpHandler
0 b6 p4 i; B: H) E6 U m: t - {
; U4 w8 Y( D: N5 W- u, ` - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池& ~8 l- r7 T4 C4 W. y6 s+ T* Q
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
% d# A0 `4 I7 |$ Z* G) x - public void ProcessRequest(HttpContext context)
) U, Q: {; k6 o" ` - {
+ T8 U, N$ t* {* u% P - //context.Response.ContentType = "text/plain";) }* l" s# K0 C( S0 a$ t, u
- //context.Response.Write("Hello World");
9 B1 m, q4 V* _& W- A' j; _) { - if (context.IsWebSocketRequest)) x( j. O2 ~* ^
- {
! G, P/ y* X8 z! }. t - context.AcceptWebSocketRequest(ProcessChat);
, c) X" S6 R) `7 }- w - }
) H: ~. q" Y. G. @ - }4 `4 ~' r/ U9 z
: I% ?, h, ^& q& L) t% }+ P- private async Task ProcessChat(AspNetWebSocketContext context)5 ?6 c" h" B; l2 q, a1 X/ I# y
- {4 o+ }1 b8 r" \6 S) q
- WebSocket socket = context.WebSocket;2 f5 g9 X: o/ V4 @. K5 U6 D
- string user = context.QueryString["user"].ToString();& L2 ?+ f: m% u" K* A
5 P M# S" R' i5 V- try _) z0 [4 S% e- \$ Q$ ?- ~
- {. W* J; z: _% X3 {$ }; y
- #region 用户添加连接池( D# e2 Q4 J5 X+ z
- //第一次open时,添加到连接池中
- P1 b; M; K/ w' u ^! N - if (!CONNECT_POOL.ContainsKey(user))
. Z' q7 v8 c1 E - CONNECT_POOL.Add(user, socket);//不存在,添加3 r G/ B) {7 `* C& s7 g( U# x# \0 s
- else
2 Q4 A' ] a; Z9 y. I- z7 | - if (socket != CONNECT_POOL[user])//当前对象不一致,更新5 F7 I3 B6 m8 S: {% S9 u
- CONNECT_POOL[user] = socket;2 F! e% J0 R$ a+ S
- #endregion% j, F& f3 f9 _* l9 |4 R, O/ Q* j# C
- # D# j5 ~) @: h) {
- #region 离线消息处理6 N$ P8 V: {4 o! z# c2 y' m
- if (MESSAGE_POOL.ContainsKey(user))
5 U6 C, ^% q# _7 c) J4 H - {
. h% @! A! {+ ]3 D* O$ h3 w. p - List<MessageInfo> msgs = MESSAGE_POOL[user];* U( q. R0 Q3 z p: d
- foreach (MessageInfo item in msgs)
; A6 z# D$ U5 {& F! z! `0 D, |7 H - {
% i' b! y: T; f5 Y6 u" N) p - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);/ `* a% B C5 T* W2 l# G
- }
3 @7 }$ j |- v4 Z% s3 L# P - MESSAGE_POOL.Remove(user);//移除离线消息
: E$ Y: Y. r* o I3 G - }$ k& L* h5 G# {% a* z
- #endregion$ w8 R3 A: u) p% U# _4 O) M- U
- 9 L) O+ E- F2 w, K Y" }, g4 k% m2 P
- string descUser = string.Empty;//目的用户) k1 u4 @, i) L$ Y
- while (true)# m. }+ [! ?* S# N" Z: {7 [: t
- {& z9 j, k9 t% }- Y! L
- if (socket.State == WebSocketState.Open)# \6 N1 q" K6 g6 F
- {
. E2 d: {" ^. Y6 T! B - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);( R& s; H8 H0 |) b
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
& A' b. J9 b8 R( y
- C2 w6 i& Z, m3 v. J: p' L- #region 消息处理(字符截取、消息转发)& f$ g' I* ^! ^; R
- try
# ^/ s; P3 H { - {/ \0 q% p7 J; X
- #region 关闭Socket处理,删除连接池
5 E6 w# v. b, f- d% o( e0 M1 j - if (socket.State != WebSocketState.Open)//连接关闭8 V. |7 e% F) p6 v
- {
, T0 G( k& G; N - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
" m& l! L$ P5 f9 h' o - break;! p% S* e7 X9 c7 ~2 g
- }
, K, R9 D* a7 g - #endregion; Z9 \5 b2 E: t+ g0 z! U4 K
- - v6 g! {* ?0 h0 ?& |
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
- B" [+ F$ R9 ]) Z# j - string[] msgList = userMsg.Split('|');$ x. b. a: d- m0 N# w ]
- if (msgList.Length == 2)) ~) f# H: Y$ S
- {
* i3 R r f u - if (msgList[0].Trim().Length > 0)
- V3 ]) O( `+ B6 A5 r - descUser = msgList[0].Trim();//记录消息目的用户
l8 f3 Q: u6 ] - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));* O1 [! v4 P- d/ Y
- }
A6 R4 R# v# r- P2 ^4 I2 k- O - else% N* h+ d. x5 U6 |
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
; c- j! e3 S+ x' L& n0 }
0 P! G! b$ |8 ~1 y4 i1 J; n' P- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
( M p( n1 Y9 W4 P* Y7 g+ p/ C' a - {
3 O3 a B7 A. w! u& I1 ` - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
1 f* D! o9 P! ]. B w - if (destSocket != null && destSocket.State == WebSocketState.Open)
_* z% C: ]$ A7 q3 o5 F ?1 H8 ?, k - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
. t' e) q0 i; A% ]8 ` - }2 ~$ Q- c$ `& m, X6 }. q
- else
( C# Q" {4 p" o - {
+ ?9 ]8 d9 L+ B+ G6 K0 \) y9 t# L - Task.Run(() =>
5 e& O' r' ~7 y& X S' K - {( G% ?. W# E4 }% p! W3 D
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
4 c( [2 q7 T* o( {9 Y8 j4 ~8 y, c - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());* `) s7 ?& y1 ]8 J; p' p
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
7 L6 L9 p- ?; ?% F( k2 L - });
1 Y8 k( h# v8 C - }, P3 [) f. Z) r8 v0 K6 D6 t
- }6 C* U" E) f3 {
- catch (Exception exs)
3 n2 |& K. a9 N w" H1 E - {8 Y* c% m1 V7 q5 T' a9 b% o
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
5 R0 }! V6 V" s; p/ s! \ - }$ i. A8 K- T9 C6 D* B! ]
- #endregion0 O; V- F5 e0 O2 F, E
- }1 @# N7 G4 B/ K! ?8 G' s; G- h& ^
- else) [ _- `/ k' D3 j' B# m, I
- {2 Z- \+ j2 O0 n9 I
- break;
2 g) D- d0 o z5 @* V - }
5 J2 s6 t' ~" ^8 Z - }//while end2 D! v9 T: S T2 w
- }$ W' O9 m9 P; V
- catch (Exception ex)
' @ ^# l4 ^9 k; j- w I/ r - {
, E/ Z3 d; Y! F3 `4 s! n - //整体异常处理
3 s0 R/ }6 w2 Q$ h - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
: Q& }$ l( l3 t+ a# @ - }
0 R, r+ o) q1 u" r, v - } T/ M4 H- ?6 g* S9 N0 O$ C
- 5 M: m: h: G/ A, u# x
2 B O+ N6 K. Y/ E. `6 Q& X- public bool IsReusable0 ^" k8 } n5 \& d1 p
- {6 c X, K! M+ o
- get/ \, g! J! v; u7 s: q
- {) A& } [! I- D) q; N
- return false;' z3 _. F; _7 A6 M
- }9 l/ y; v! n9 r I! ]4 l
- }
# w7 m/ m5 l8 z% G+ J - }' J$ ?7 \( y7 R2 m3 G4 E
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
; t# ~: h' p, {/ d$ n- g+ g |