服务器端代码编写 1.新建一个ASP.net Web MVC5项目 $ r- Q( m: |; K% h
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
# `) t1 Z% k( X2 h# H8 E) Z - using System.Collections.Generic;
' `0 _) o# e$ t - using System.Linq;
1 R6 t$ @% {0 P! h0 r6 L5 K" r. r - using System.Net.WebSockets;0 O! Z5 _# ?# t4 N' r1 c
- using System.Text;' R2 c4 U5 r5 ~- V) f3 j- p
- using System.Threading;0 M5 o9 u8 _. U& B$ n$ l* g
- using System.Threading.Tasks;/ p# b: `1 B! f+ h
- using System.Web;, i8 f' g# l7 m H x
- using System.Web.WebSockets;7 P2 U9 A! n( Z( ]
- # e: D3 I1 s; ?7 Z, l
- ) g; f1 y( i7 b: |
- namespace WebApplicationWebsocketHandler/ p) c6 q7 W- ?$ u
- {( c. G8 |3 i4 H2 t. L: c+ O
- /// <summary>
" F8 r0 a0 e) P1 e - /// 离线消息
5 d# z! O2 \" v3 Y7 S6 Y- f: U; W j - /// </summary>
3 l4 Q( g3 C- B. c, { - public class MessageInfo
* l6 Z$ J6 E! ~/ D/ { - { x |8 m( `6 b! `! X4 K8 `
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
0 s5 k) Y- o! F+ I - {6 Y& e- M% v6 W) z1 _" ~3 ]
- MsgTime = _MsgTime;
- N4 g5 C- [! ?; v7 L - MsgContent = _MsgContent;
; ^* o& Y6 J1 k: A1 j9 g3 | - }
9 R7 [/ o, Z$ b( L# Q T8 M - public DateTime MsgTime { get; set; }
' o7 T# V$ @3 M+ E: M4 r - public ArraySegment<byte> MsgContent { get; set; }
0 Q) ^' ]! y3 K8 L8 [) N - }
& ~1 s7 ?+ l' \+ X2 M9 O% c - 4 U3 u! W* l7 L9 v8 |+ b7 R
% u- U6 n4 K( q& ]0 L
I4 ~ f* w" H; G* D, g
+ B2 j, X! H# |6 w* [- /// <summary>) u4 v2 I/ S9 f6 d7 L
- /// Handler1 的摘要说明$ O$ V/ k* ]/ {3 L) D+ n
- /// </summary>
& V/ H. k% Q; A% H0 s8 {' c( J - public class Handler1 : IHttpHandler
6 z, X4 J' z: Z% B1 Y - {
. y. H6 C3 ^1 z" P F. f - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
: c$ T/ x) U4 [. {& _' J - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
2 O* s- p0 i& h& v% U' J! z - public void ProcessRequest(HttpContext context)& Y# H) X" c5 R0 Z- i1 ^$ K- Z
- {
u2 w& G4 K8 y: P( R u - //context.Response.ContentType = "text/plain";2 L& @: J" R5 m) q8 s
- //context.Response.Write("Hello World");. ^+ z1 `/ B3 v
- if (context.IsWebSocketRequest)
) Q! M* n- q5 U - {: D _3 Z0 A" l! a' ]9 G I: [
- context.AcceptWebSocketRequest(ProcessChat);5 A3 m' ?" y" q; Y6 h
- }
$ a2 ~. B0 B2 D* a: w6 ` - }
' \& i0 E9 G2 C/ ]. X) A
9 N5 {2 N' ^9 v3 y- private async Task ProcessChat(AspNetWebSocketContext context)
1 m/ E- S' B" z W7 X) q - {
( J8 h* i$ ?% h# q% P! S* g - WebSocket socket = context.WebSocket;
" G" V: S: j+ M: |, b - string user = context.QueryString["user"].ToString();. ~" {$ K/ N5 Y, F5 E% ~0 ^
! p/ A2 l/ G( Z/ H6 A- T- try
2 u1 Y" B- y7 ^, L% V - {4 H) Y6 {. W% U& Z5 e* ]2 Q
- #region 用户添加连接池, {7 A9 ~9 |# w4 Q7 F- U
- //第一次open时,添加到连接池中$ v* t2 b! B: I3 o# Q, u/ D
- if (!CONNECT_POOL.ContainsKey(user))
6 R, { F+ v* n; j" Q6 h. i - CONNECT_POOL.Add(user, socket);//不存在,添加
6 t. i( i4 W/ ?; p - else
8 o+ u6 t: ]7 K" W/ P ` - if (socket != CONNECT_POOL[user])//当前对象不一致,更新5 |( B7 ]+ L- J1 C
- CONNECT_POOL[user] = socket;
, |+ [8 }8 h4 R% M5 n - #endregion
, t% v" `2 g$ {/ T' y7 F4 @6 Q
) i; Y. k9 F' W' V( x1 S/ o# G# A- #region 离线消息处理
6 W$ n8 s4 s) @5 K. l. G) D0 y - if (MESSAGE_POOL.ContainsKey(user))8 ^" I2 G0 R: d$ p
- {3 R! Y. S6 c# n) _+ |( M7 m- f
- List<MessageInfo> msgs = MESSAGE_POOL[user];
% w3 m/ ^% d3 q - foreach (MessageInfo item in msgs)
/ f! T4 E8 `* C* e6 K0 \" Q - {( f" |$ @. l4 w
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
! G2 c9 o3 d' L1 E! F8 [0 x6 [ - }2 j2 r2 W$ T o
- MESSAGE_POOL.Remove(user);//移除离线消息
; @: G8 N b" M6 P Z" q3 c; l2 C8 m - }
- r1 ?* r% k6 D2 J - #endregion( Y1 g" q; N; x& p
- ; M9 i$ Q+ w% Z) n) Q6 g
- string descUser = string.Empty;//目的用户
$ ^$ Y; ^9 N/ e8 {% \ - while (true)
& H# `6 ^7 @* E+ C8 y - {
8 A, T, M7 x& L8 H6 q z/ Y - if (socket.State == WebSocketState.Open)
, A6 w: t0 R1 ?) U2 E - {1 [, C+ N0 k( |( P" c
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);5 O- w$ L, N( }; O. }
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
( A1 c2 [: X+ K4 J6 m. |( J - & D, P5 g! p$ l ^$ Z* ?' B
- #region 消息处理(字符截取、消息转发)
* ~% P/ _- Y& @3 W+ w3 c o0 Y - try
# _: h3 V0 D: t6 ?6 ~/ O - {
( |' L# i; H; g" ~ - #region 关闭Socket处理,删除连接池
: t0 K/ q9 H: A+ S+ c* H: f/ u - if (socket.State != WebSocketState.Open)//连接关闭8 ?7 r4 L, u3 J+ N9 }2 ~
- {' A! x" d3 F$ x5 H8 v( [4 d
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池! _' g) J* Q! x
- break;
$ f4 A3 I& I4 g/ h' d) m) g- Z1 T, t k - }5 F' \( T7 o U) g$ G( B3 ^% ^
- #endregion& ^0 O! `- h r
& Y1 g, J' _$ _+ z- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
4 q* S7 g) H+ H+ D# H* s - string[] msgList = userMsg.Split('|');
* S- M* r1 [3 ~1 C' r - if (msgList.Length == 2)
3 T' {+ ?) t- j1 j f% Q0 k - {
/ {# h( u! K( U: N# S - if (msgList[0].Trim().Length > 0)
- |( N }- Q& d' I9 o - descUser = msgList[0].Trim();//记录消息目的用户* O/ k/ z3 i5 n
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
: k0 U4 H9 e$ h, ]/ G! H0 ]# t - }. w4 C: O* y! `# B; \
- else
( z% {# T4 R* b6 m - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));: m& y* V6 \) ^1 T+ D
% J5 O1 \, g3 k N6 ~/ E- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
' @$ N# b" x1 I, F5 B4 h( { - {1 k) j+ T7 d, i9 S% W1 B8 W
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
* }) l5 B+ R2 {, _+ c. b7 R - if (destSocket != null && destSocket.State == WebSocketState.Open)6 x8 t1 p% o4 K: G
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None); E" b+ Y8 n7 o* \- X4 j5 g
- }
' y4 h! d: | U2 ]7 d* O - else
7 u5 U2 Y% U/ O/ `, y - {
4 k: R5 `; ~( O/ W/ _ - Task.Run(() =>
# `/ r% g+ v$ @1 ?, h% r - {
8 h& X) [( n6 S& O - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
# N( W: t: `2 m/ a7 R - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
; D5 a t* z% }' E3 b9 G - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
& ~" }" `3 b+ l" e. B, j - });
* i, Z2 n% ?+ G" z7 L/ W3 h% u9 Q# ^ - }0 r9 O* z" q) m# V$ H L- e8 V
- }9 m+ ~% }4 J5 h/ F p9 d! a; D# h
- catch (Exception exs)
- S4 g4 z) j7 K - {1 L% [$ ?5 L$ R5 z; e
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息& r: ?7 E, M& h4 K" ~3 v
- }) h9 R4 `* [0 }: l! t2 A2 {
- #endregion" h7 H* C" f, h2 I v
- }
% Q3 n/ a& H+ S6 c( s6 V - else) U3 R1 H6 C7 q: F" U4 u4 P% ?
- {
* O! {+ z' u" O) |/ P - break;) j/ E O! l) j* Y4 c: `3 X
- }
Q7 H! u) _0 O- _6 k- @ - }//while end
# Q1 K4 k+ F+ F6 L4 O1 t, P - }
0 C( y3 G" V+ J. F4 [0 ^7 l - catch (Exception ex)
6 b. t) D) v/ B* o; Z( l! v - {
4 y# C0 R8 g* D- [; ` - //整体异常处理6 U1 o6 Q: p _1 ?( k+ s0 j( u
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
" j$ V( F% ^! g8 } | - }
$ N" U, J' ^# _6 g5 j' i - }
% B& A# O8 S9 N) y6 ] - , S; n q4 @( O t9 g" \
- " ?8 e' N) m( V( B. y1 R3 Q) U
- public bool IsReusable& w& R6 b5 |; P% }. S6 y
- {3 v: R0 c! `% P+ s7 A1 P
- get5 D- U: f( t/ O. U
- {) I7 `4 f' `7 \9 `
- return false;
, S+ C9 `) k+ A& P. T - }$ b ?0 k& h5 d& |% `- [
- }
6 w% N% C2 O2 o5 q - }9 y9 E7 C) A! m' j7 `
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
. \* v- {" U( [* f. X9 U+ P" e |