服务器端代码编写 1.新建一个ASP.net Web MVC5项目 ( ]% X: h* g8 W5 T+ [- Y
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
. G0 c: {4 V( y' d# x# l3 a - using System.Collections.Generic;
: t& }# {9 h0 |" z - using System.Linq;
* @& R9 l0 R7 M2 R' b$ ~$ l; h - using System.Net.WebSockets;+ F. g ^1 I" b+ T, a! y
- using System.Text;7 e" P) ^ c, E. q
- using System.Threading;
1 H6 m& i }9 l! ]6 o. L - using System.Threading.Tasks;
" a) A6 M3 K0 Y) k - using System.Web;
- J- ~- ~3 l4 d9 c6 c- ` - using System.Web.WebSockets;2 ^) ]# I8 }% F3 z0 F8 s" p
7 P+ ~ t# u) U6 t$ U5 c$ E
, {$ i( f% e, r6 z9 s6 U7 A- namespace WebApplicationWebsocketHandler" T" Z5 d1 f7 N- t; }$ M
- {
7 _/ K4 _8 i" G# L - /// <summary>
; p5 p5 s- [% U" c( V7 ?& J - /// 离线消息9 t9 C+ \1 t9 c% ?3 g% r1 f% E& q
- /// </summary>
# s- a! o m3 e6 v7 h - public class MessageInfo
5 F# I4 i4 i' h2 R. s - {% m& {. l2 ~- H9 b. W
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
, p/ @$ L+ {9 P7 g- E - {
4 K- @1 ~: t; u - MsgTime = _MsgTime;. `, ^# A4 W. E$ \
- MsgContent = _MsgContent;/ |2 @$ W2 Z/ m' v a8 q9 k
- }& g! h/ D3 P' o# ~" Q1 u/ l
- public DateTime MsgTime { get; set; }' x" y# k% F1 b0 V8 D) {. L
- public ArraySegment<byte> MsgContent { get; set; }
; H8 a7 i: F4 h. K- i3 B - }) O+ i: L& U7 A) b
: E8 r. [) z5 Q; E# k$ h( D/ A- ' u2 ? z% H& D
- / C% s# Y; O' V
- # X' h4 z% _2 k& l* P i, I) d/ b C
- /// <summary>! }% j; P* O+ }- p" @- `9 p: y
- /// Handler1 的摘要说明
6 _; g& ?' t7 t/ }* l" \# n: _ - /// </summary>" @* r; G3 T. a0 Y
- public class Handler1 : IHttpHandler
5 ^4 b8 T7 U: e$ P" u8 } - {0 d9 P! f; S1 y
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池2 S7 D4 ^% }1 z8 O4 W g( r$ o9 [, G
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
( V* G: z' @1 Z' t$ [ - public void ProcessRequest(HttpContext context)
$ e/ t' P+ q1 q0 W - {; e6 f1 ]( Q8 i! ^# p
- //context.Response.ContentType = "text/plain";
; [/ S! V% H2 ?+ E. n4 \% y1 C' s. r - //context.Response.Write("Hello World");
. i% I8 [" r- a - if (context.IsWebSocketRequest)$ l# O. `! T3 h7 S7 m0 I
- {
. Z0 y( |4 W" x - context.AcceptWebSocketRequest(ProcessChat);4 l# ^2 n! D4 c% T' B/ a8 b; X0 N
- }
! \( ?3 Y5 I5 |! @ b3 C" h - }4 C9 k5 X/ b6 p$ [, V" Q
- - F& Y# D/ c2 }6 \3 A
- private async Task ProcessChat(AspNetWebSocketContext context)
3 K8 B- e; R* x. s. f - {
1 i, o9 [9 W5 d4 G - WebSocket socket = context.WebSocket;: i" h) W/ _0 |1 v, V
- string user = context.QueryString["user"].ToString();! w# ~: T, L! ~1 d' D) [
- 7 y( o5 n/ X: u# R) {% w
- try
1 h% _( _! d7 n3 a4 h) v - {4 |7 ?$ p7 E0 P; ~6 O
- #region 用户添加连接池. [1 ~7 o% L m2 M! r! N4 E/ K6 k
- //第一次open时,添加到连接池中& m, \6 C W+ R2 C% Z8 }
- if (!CONNECT_POOL.ContainsKey(user))3 ^2 _$ I0 Q& q# O% e8 u
- CONNECT_POOL.Add(user, socket);//不存在,添加8 ?0 a& [0 f; K
- else
) i# L3 P! Q0 Y A* e& [9 G- \& m - if (socket != CONNECT_POOL[user])//当前对象不一致,更新1 i9 }) {* O, J+ L) T
- CONNECT_POOL[user] = socket;( k; u( i% I+ F* F$ q/ y
- #endregion
; V6 D& ^" c( S g5 Q - e4 j9 l! q, l) i, B
- #region 离线消息处理" W W I0 L4 S0 [, t7 L1 N
- if (MESSAGE_POOL.ContainsKey(user))
9 S! ]6 {4 { | ~; k0 k - {
q8 S5 W' T. ^ - List<MessageInfo> msgs = MESSAGE_POOL[user];
! E/ }- G% b- a) e+ j - foreach (MessageInfo item in msgs), K. j9 l, W2 U0 R6 J% e
- {
' @' V- G9 Z: {# b2 R' `6 b' i - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);+ B$ x$ L+ W/ v5 d2 L
- }
3 h- H& f; Z3 } - MESSAGE_POOL.Remove(user);//移除离线消息
: k! o- [$ }; b. _' ~ - }
; h% W8 T# X# l4 V' @4 U$ | - #endregion7 l5 W0 D8 Y7 Q2 s$ ^3 a
7 ^$ H% j$ @* Y4 m- string descUser = string.Empty;//目的用户' U T" U* k5 v2 k; G( g6 o
- while (true)0 |6 i3 D8 U& f& ]7 R
- {
! y- F& d! f, n: ?. R7 C - if (socket.State == WebSocketState.Open)$ w, s7 ]% c8 F5 Y& [3 O' T m
- {6 o P; y) c5 n2 ?
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);6 B# Y, t s G/ l. X% N9 d
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
) A% t, v7 T( O( k/ V* A$ L1 V - 8 ]1 |2 n8 ]* } } H
- #region 消息处理(字符截取、消息转发)
. l( O* l# z, P, X8 z! o - try [7 F6 \' G2 ^9 \% Z2 |
- {
Y1 t2 M \9 b4 |7 j" m" \& \+ l - #region 关闭Socket处理,删除连接池
6 e' a9 m+ ~* S - if (socket.State != WebSocketState.Open)//连接关闭8 k! ?# H, F4 U! G* r* @4 |+ I$ V+ G
- {2 |+ T9 s4 O/ Q+ Y
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池* X+ m$ I4 T2 r, P' T3 V; O* A- g
- break;
' N9 O; g# h8 L W+ f; S, @! ~ - }
, k6 T( W3 ~; w8 B - #endregion
5 J' M6 l& v$ }( d v! Z4 q4 r% n
0 d3 A4 `/ O9 D- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
5 r' X, x% } j* z3 h* O9 W - string[] msgList = userMsg.Split('|');
[8 k! y* Y/ u" }5 n3 w1 ?! Y - if (msgList.Length == 2)2 f3 L7 f7 s! C4 s
- {+ ~0 V+ C8 d& [: h1 H
- if (msgList[0].Trim().Length > 0)
) k9 B7 x* ?) a, \" o - descUser = msgList[0].Trim();//记录消息目的用户
8 A; {; L, C' C8 I6 z) O - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
* s" k; Y" d2 r - }- j+ ?. N6 F% b, R
- else
$ ?6 C# C" M( y& P$ I. v - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
' v, `, A- M, z9 P6 l
7 ~' t5 [( Z' p+ ^ w4 W" Q+ M- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线, G) A& m# J% m& ~# Q% H! f
- {
: l M" ~" m) F; p, e+ ] - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端( L3 [; z( \2 l
- if (destSocket != null && destSocket.State == WebSocketState.Open)
( P0 F" K. Y% w* C0 ~1 ^ - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);& m* l$ }. T8 l! C+ ^7 D/ i2 Q8 F
- }- X1 n* _7 O+ b8 s% j5 |: G* i
- else& ? ~( P6 Y5 }: c8 d
- {4 t0 d, O3 T- d& c) R
- Task.Run(() =>
+ N" q5 X7 m- |( U - {' _6 `) f( i: D# P; h6 E
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
% u$ Y- k% o- x* Q6 Y1 X0 l - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());% a7 e2 {2 z' c
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
$ a& Z/ a$ k8 } - });
* \% I* |4 S3 R& |! c: H; a - }
! d- F8 U6 |$ J. R( c# q - }
- {, q) f6 T8 z - catch (Exception exs)+ q) T _( Y( m- ^- B* `* I6 t
- {& _' [% i. \: n' w, A) C
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息8 f; ^" B1 K- n6 ~" r8 ?' b
- }
# d$ n# u5 p5 u, | - #endregion; N4 D5 x0 E% d
- }
6 j( f; t- d, i4 g. J - else& H4 g9 P, O1 N, d8 y
- {
) |5 f$ A" E: y6 I/ A! s, V - break; x9 o! t8 _. Y; ^+ A* B
- }+ w+ Y8 P5 e. \" c4 ~
- }//while end
1 d+ x3 Q9 d* m4 v: H& G# \ - } L, h% H3 C2 ?0 E: K J
- catch (Exception ex)8 j) x# S) w9 \. ^* T! A
- {# g) j2 Y" P" C0 m
- //整体异常处理
p. y3 T3 G+ R* @2 K' Z - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
5 _5 j$ ?1 S% y% U$ @: V4 O - } {2 o* } C- E
- }+ G# E& S0 D ~" ^
y0 @0 K: y4 a, _- 7 g4 f5 [% R; o
- public bool IsReusable
) N/ z F+ v, x - {
' {& F2 z3 v/ W* B3 d- Q) m( k - get
0 T0 }5 _4 g6 t# H - {1 @, P! ]) T+ \/ W" V, u3 ~
- return false;
- o: J& t+ v0 s9 W# X, N - }' A K' ~1 R6 n3 d4 d3 ~3 @4 w. q
- }' C9 C8 \# Y2 S1 {
- }
; |2 T8 y7 Z, h' e - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 $ X: ~# G9 c* `4 |
|