|
服务器端代码编写 1.新建一个ASP.net Web MVC5项目 * m0 _" @6 C" [3 i) m! Z
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;! D, F& F' j* [
- using System.Collections.Generic;
& D t8 K; }9 s1 S$ m - using System.Linq;
$ I# b, B/ j. X, ~ - using System.Net.WebSockets;6 S- L+ q p. s% k
- using System.Text;
& U, z. M& b& i5 x - using System.Threading;
* u9 J% a% b ~; i0 v9 i' P* \ - using System.Threading.Tasks;
" z. E3 [ L( b9 f @5 X - using System.Web;4 ]1 H* r6 N8 ^; Y' r6 E* l+ w* A
- using System.Web.WebSockets;
( q F @% g! [3 I" s - 5 a+ F0 d2 \. q$ M9 c( M
$ k# N" f6 L9 X' \- namespace WebApplicationWebsocketHandler
4 d0 D# _* g$ Y& s9 i - {! \* c" E* }7 q- b6 q/ G
- /// <summary>
~% v/ M* }( b/ b5 }8 M6 O: l$ o - /// 离线消息, @- h) x. ^, t
- /// </summary>
2 b* R, m3 Z# N) l; @' E! |$ D - public class MessageInfo) q# {: d2 f1 M* c
- {1 L7 {! o* X+ v4 @9 |! _9 p
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent) l! U: b& i T& t7 R& f
- {' J M8 B- O: W, C) {' s2 J
- MsgTime = _MsgTime;# I$ U; s+ N6 p+ b$ y
- MsgContent = _MsgContent; w- }) L! i" n* h
- }
0 u+ A- R" c* J0 v8 z5 _5 Q2 v - public DateTime MsgTime { get; set; }
) W* Z) H/ g/ @6 k+ F! _0 [ - public ArraySegment<byte> MsgContent { get; set; }# r# e$ Z9 S8 b+ j
- }
+ b* A! m# v" {# o8 G. R - 6 i6 v, \( q, p5 ?
5 _! a9 w, B8 U6 G* N: V$ g
; ^" C: ^0 i, Z8 e- 7 u( V9 A7 F; v
- /// <summary>1 M( |, \/ M- a* d5 c
- /// Handler1 的摘要说明8 Y6 Q& t, ^7 `. P+ r! _
- /// </summary>8 _3 n6 y' o' c$ P& m1 @$ Z! i
- public class Handler1 : IHttpHandler
8 Y# R* F8 I- |9 [ - {
[! I% K: `7 h: `0 @1 I/ q3 h9 ~3 A - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
0 q* O1 Q* i4 E5 |2 a9 p" \/ y8 ` - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池. R+ b% L: F ]. Z# m, G, Z7 t
- public void ProcessRequest(HttpContext context)& L1 Z5 ~1 k0 \) R; s* a* z
- {
: v, N1 A; D. ?( S - //context.Response.ContentType = "text/plain";! m, Q1 R" [4 W' U) q5 p% |) D
- //context.Response.Write("Hello World");$ ^* q+ C: o, [7 n6 z$ m
- if (context.IsWebSocketRequest)+ Z k2 k$ q* Q4 F
- {" v: E8 Y# U, L# c8 p
- context.AcceptWebSocketRequest(ProcessChat);
. _. g H; j6 r9 o6 A0 A - } 3 k; f y8 ?0 E! X% P- n/ y9 O9 Z
- }
( d: i; N" M0 j/ U - . f5 ^* ?+ B9 f+ F- A
- private async Task ProcessChat(AspNetWebSocketContext context)
: j6 k5 x6 Z. z# V8 C - {( o5 J& U/ A. d* X3 ]
- WebSocket socket = context.WebSocket;
: q1 P/ O" L6 z, q. ]# H% |. p+ q - string user = context.QueryString["user"].ToString();1 a. p( t8 v4 l! Q2 F: h ~8 r
% k" a; i* l7 z2 ^* A6 T9 a- try
# P5 ~% s: ]! U; ]0 _) G - { Q7 r3 F3 g1 a
- #region 用户添加连接池- B. g' x' u v7 c T
- //第一次open时,添加到连接池中
4 @( j/ O, C$ \ - if (!CONNECT_POOL.ContainsKey(user))
( P( e& C4 l6 c7 t4 o: T - CONNECT_POOL.Add(user, socket);//不存在,添加5 e2 M6 f: s/ R9 g5 D
- else! U' J- E; g& e+ L" d4 E1 ]
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新 d9 N: e& p; O2 a: E4 u
- CONNECT_POOL[user] = socket;
1 y( j: A e2 n - #endregion
" m2 \1 x) u( ]% a% z0 N7 h1 @: V - + q2 E$ a* n Z
- #region 离线消息处理
2 @+ ^+ Q p7 k' ? - if (MESSAGE_POOL.ContainsKey(user))2 e/ t/ j: b* p! ]" d* P3 k
- {: l" Q0 I' s3 e! S! e$ K$ H
- List<MessageInfo> msgs = MESSAGE_POOL[user];* j# q( ]& U5 _2 I
- foreach (MessageInfo item in msgs). r' b3 m( j# R4 T) ]4 m5 D
- {3 p. R6 q8 f3 f+ m2 L5 l
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);. U. ?* W" o' |* ]7 M
- }
) ?' q7 u# i4 k. U/ E - MESSAGE_POOL.Remove(user);//移除离线消息/ z8 g9 g4 s$ G+ |
- } Y: O5 T& V2 h: p J3 c
- #endregion
- v+ C2 {- P( Z - 8 `/ F3 f L8 w2 S% O& L6 n, p
- string descUser = string.Empty;//目的用户# p8 N4 Q8 @" c6 s% a$ F2 ^7 r% [
- while (true)
; R: P) S! o& x6 G8 d - {0 u- N* Y, e7 f/ W/ W- }: X! P
- if (socket.State == WebSocketState.Open)
* \) x' R* I. y - {
! ?0 O2 ^' V5 B- q; f, w - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
: x9 ~* h# c4 A - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
* o9 b) s- d( Q1 x* ?
' \/ [% |: B4 ? I3 [- r- #region 消息处理(字符截取、消息转发); l. f4 T) x- J4 ~6 G; y/ X* a
- try3 t1 _# P: ~! o4 I4 F$ u
- {
" L$ `% l0 d Y/ Q5 [% K - #region 关闭Socket处理,删除连接池7 [# X3 P) O+ b! @1 E
- if (socket.State != WebSocketState.Open)//连接关闭6 R3 D0 ]' e: u- `) z* {0 m% r
- { \- g$ l1 r0 X5 { R
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
* |! B2 G6 B( y F/ v' p - break;! w- N6 v W2 d' X/ u
- }9 {8 E( o7 f% y& K" T# u m
- #endregion6 [9 q# F+ |# ~3 l" H7 [
8 w7 q/ y& U8 @- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息1 B2 A3 u, T+ `
- string[] msgList = userMsg.Split('|');
% d$ c# t( @2 i( N" ~+ L! s f - if (msgList.Length == 2)
. i! `( t1 {* d/ ^# b3 ~ - {
* V9 S! {! n: e) Q1 J - if (msgList[0].Trim().Length > 0)8 v, Q' [* N! K' f% v
- descUser = msgList[0].Trim();//记录消息目的用户
3 k; h, B( x, s! \2 T ^; I7 c - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));5 A* H8 c! q# {4 a5 b# _) Q
- }1 J9 |1 {1 d) s
- else
, H) e# m; F0 t1 l( E - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
* V6 E5 x! u5 n4 P }1 i) U
2 _0 K4 T5 l; C+ r' C- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线1 v& `. B0 K* N6 D; M
- {$ @/ w8 a" @+ Y2 u8 B; z
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端0 x5 ^* r+ V) M) ]
- if (destSocket != null && destSocket.State == WebSocketState.Open)
1 [: _4 z7 w+ F4 F' I - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);0 r: H5 e5 @* z4 {- b/ {
- }2 I" l' N% y1 [9 j7 E' i- c2 D/ a
- else' w9 O' [+ j& E
- {. F9 k& R% }' u& b: x) H. W3 q
- Task.Run(() =>$ ]" @ D& J7 D" J( W' X
- {$ X3 Z3 `* E2 A0 g, k
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
9 c+ K4 d$ K; n1 O - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());+ h, n8 r- d( S0 ?. H
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
4 Q1 W/ K6 O9 q% Y2 O k - });8 K7 _: `, l y7 U1 n3 o# j" a
- }
5 E6 m/ T* u& ^! S. k - }/ b' [5 e2 |# c# a; s' O
- catch (Exception exs)
: E, H) X9 Y' {: x - {
7 f% \% x7 [4 I7 H$ L - //消息转发异常处理,本次消息忽略 继续监听接下来的消息0 r" Z; W( I# q# e1 y
- }
7 f! R+ ^* F, v( X: m' M0 o" ^1 f - #endregion
G& A' o. S$ V! f$ ~ - }$ u% o$ y: m7 ?/ g9 H
- else
5 t0 K* f% @6 T$ k - {( S; P" @; X" ]+ H) e" w
- break;
1 W& H3 ?2 @; `: w/ N9 \; x - }$ ]1 d5 R( y! f; I% `* f3 y
- }//while end! N* V9 a, {" M9 g
- }
# H1 _& q; d; b, D* v8 w# ~ - catch (Exception ex)
. ?, B; k+ V$ Q7 k' ~ - {2 P/ j5 A8 }2 n8 w
- //整体异常处理
( F" D/ i# q$ U - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
* O! h6 Z; T9 Z; t - }4 z& Z6 I- x2 R; |% G# x# Z) ]
- }; x6 x8 k Z" Q9 V8 t; t; N
- \# h6 @, ?& r2 m0 d
- $ R4 E2 Q# n* N$ K7 a' o3 ?/ t
- public bool IsReusable
5 s# ~0 x' A# m T% ~% | - {( k* S; [% z; p/ m3 \3 [+ T
- get0 C9 L1 _( n2 V( d0 A( H& }* v
- {0 U2 J4 ]5 J3 v6 X. K6 z( [0 A
- return false;
6 w6 N: t5 K9 f3 H - }
) n# P" V: c t8 y& N; C7 x - }
# X, a" w' b, m, q& f U6 G - }
) r. n7 i% B, @* Y - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 + m5 |/ g$ Z% W4 ]9 R
|