服务器端代码编写 1.新建一个ASP.net Web MVC5项目
D- c, {2 \- M, {/ U$ T% y2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;( I+ S( z8 ^: O$ h# G( N$ T
- using System.Collections.Generic;! N/ C7 }/ p: J
- using System.Linq;
! e+ b H+ h5 j; f e; G; W, q - using System.Net.WebSockets;; K2 I# K7 [8 {* [
- using System.Text;
! q* C3 ?& t: @2 ?! F/ T - using System.Threading;+ P F8 G G( O( H ]" _
- using System.Threading.Tasks;
8 j& L4 V& U) T4 h6 Y - using System.Web;
. H5 n4 L4 M: _/ P: B - using System.Web.WebSockets;
8 B8 J8 K( D2 o
. Y. c0 t; l" C1 Q, v
# I O- { h+ E, s" }4 O4 e- namespace WebApplicationWebsocketHandler
% u; `: N/ t, O! R% F1 V$ r% ? - {
* P7 \7 M4 K4 n5 I - /// <summary>
8 N, _% R% ?$ R- f' a* D, ?/ J - /// 离线消息
6 T, P/ O$ `. G* a' Y9 J - /// </summary>9 x3 ? l# c6 t1 ?& R, a
- public class MessageInfo
6 V2 d: F# |; B9 C - {- n( X1 t. Z" D6 M
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)8 W: h5 Q ?" k1 ^! Y3 v4 I
- {
/ q! k/ j7 @& }" Y7 I - MsgTime = _MsgTime;
$ L- }7 d- \+ ^/ B - MsgContent = _MsgContent;! g: g6 }2 h; ?; E9 ~
- }! O" k# J3 x2 n" p
- public DateTime MsgTime { get; set; }: x% E/ `; l0 |
- public ArraySegment<byte> MsgContent { get; set; }4 N& n( a& m: X$ M5 S
- }
1 H- t, X1 G5 Q4 G* S - ! y/ A' Q! ^6 v0 G; F
0 S% ^3 N: ]9 b6 W/ T4 \: G; ?- 6 ?: O. U$ b- Y8 w
. ^: ~4 E6 c+ Y( u6 ?' F; O. {- /// <summary>. w( A0 g- `2 A- R* l
- /// Handler1 的摘要说明
6 T; c8 r' k) I9 {4 m - /// </summary>
! n" T( c+ w- B, F( Q$ s - public class Handler1 : IHttpHandler
`# K" i2 o2 C( f( k - {
& _9 L: R0 `( R0 b' V( D! s# f - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池/ Z: H& P$ I2 l& k4 A8 K2 S
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池) v1 N5 Z& V6 R: Z
- public void ProcessRequest(HttpContext context)/ O! ~+ I5 A3 u6 Y6 W
- {9 o/ ~9 s1 Z: ?1 P$ @
- //context.Response.ContentType = "text/plain";
4 N( J. W9 C7 X# v3 x0 I - //context.Response.Write("Hello World");% d, I, I: G& |/ D) \
- if (context.IsWebSocketRequest)
$ b. z ?- V" Q - {
" m- ]1 U9 b7 Q' O$ U5 W4 T - context.AcceptWebSocketRequest(ProcessChat);
6 G9 |& Q4 n y5 I. }+ A- } - }
( K9 o6 Q% {' J: ~' W/ N - }
, Y# r3 H3 p; q R) `
6 e" ~9 S+ c8 _4 s! X( s% O- private async Task ProcessChat(AspNetWebSocketContext context)
. k( a+ z+ J* H9 \# R* h) {) z9 b - {* v& V2 O3 {8 G* N6 z
- WebSocket socket = context.WebSocket;
, B1 |3 N9 E* C _1 g3 M - string user = context.QueryString["user"].ToString();8 V( C& ?! Y3 u5 ~* C! A
- $ s* ]3 {$ c" F- C: y# }
- try
! W& c! @ @# Y - {
! n$ |1 x& Y# s - #region 用户添加连接池
! L3 J" o6 H9 }* T4 Q. u - //第一次open时,添加到连接池中
, x2 k* N/ L9 H3 X - if (!CONNECT_POOL.ContainsKey(user))
4 S( @; ^, V/ \. S - CONNECT_POOL.Add(user, socket);//不存在,添加% g! o& H) n5 i' N
- else& b' a6 y) i3 U/ r) z w
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
+ y, X' H8 Z6 W% \$ }3 ]" E - CONNECT_POOL[user] = socket;! r3 o8 {1 c+ \
- #endregion. N+ _, f. c$ {) }1 n7 M( L
- ! l% w' z2 \9 E( N) L
- #region 离线消息处理
, I/ w. h" n* z3 z - if (MESSAGE_POOL.ContainsKey(user))) `+ F0 a, U6 r
- {
" y- V7 f+ L; C0 f/ _0 P& o6 @ - List<MessageInfo> msgs = MESSAGE_POOL[user]; O( T+ q( t: W' S0 L
- foreach (MessageInfo item in msgs)8 j/ F- I8 d# ~" u. ~+ `
- {, m/ T6 M9 c& |3 ?3 b: d
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
5 b6 o/ h! i& l1 l( ^1 c: j5 \! L& m - }
/ X2 A8 `0 b( }$ s- Q) ^ - MESSAGE_POOL.Remove(user);//移除离线消息
" E+ |; K5 r1 O! O0 c - }
3 D; b! @- ^% U. F8 ]8 [ - #endregion' [: ~# Y6 ~% o
- % O. @# Z6 C' Y; {6 R' N& _& d" _
- string descUser = string.Empty;//目的用户
6 |/ K6 R% i o: Q; x - while (true)
, H; q& m/ |- V# M3 ` - {
+ |% ^, U; s* y, O0 _" f U8 o4 B - if (socket.State == WebSocketState.Open) L3 V# H% O, H6 K# _4 f
- {
0 ^ o: O' a" D' Z1 ^* Q& T - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
, X& _2 d/ j2 I1 ^9 K - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
$ d' u; G4 D# H% K4 x
9 e- R; s* l# i; M, T- #region 消息处理(字符截取、消息转发), w! O/ J; F0 J$ `2 v$ w/ h
- try
; U# O# D, h e5 [3 B1 q& C3 g - {
, c2 f! l+ \; ~ - #region 关闭Socket处理,删除连接池; @9 L% v1 X7 z, r$ [
- if (socket.State != WebSocketState.Open)//连接关闭
- ^$ r# ]; j2 i \/ h - {
8 X4 y3 i; z$ A/ a; u - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
, A& c. C2 R! d o0 @ - break;
7 W: e9 X# l: m6 u0 r5 {* o& x - }
7 ^6 f: h7 A y) l! M - #endregion
- D2 X) ^% E+ Q2 I( d- N* y0 W - ' a% h! N1 B! e+ l1 K8 W7 F
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息+ Z: z9 R5 @! O% ^+ ?
- string[] msgList = userMsg.Split('|');* q' ]7 Y& c6 J1 L7 P
- if (msgList.Length == 2)& q& y" `: V# @1 B8 @) h
- {
7 I% H( O' D$ {# o' F$ \ - if (msgList[0].Trim().Length > 0); o/ Y1 _# M) ~" O% I# ^
- descUser = msgList[0].Trim();//记录消息目的用户
4 r. S- z# S. |, u+ P# G4 H - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));8 ~' p& @: ^ O O/ P
- }
4 n* S9 h+ Z- V+ I$ a+ ~- c( x - else! K! H ]) z: f+ A- y$ Z
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));: i# K9 H; |) @, g$ g
! O" U# F3 W* }6 q- h* `% t- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线! a2 C! O; x8 U2 q5 x; f, B
- {' S+ u& H @& v
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
/ F3 z) w3 x4 e! ]" L; [8 h* @ - if (destSocket != null && destSocket.State == WebSocketState.Open)
, `( D K) g. \+ | - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
+ a% G! D/ v3 ^/ t - }$ {% J2 `0 }; n( b3 B
- else$ I! |9 Z. c1 A# m: Z' t
- {8 L) Q+ q9 P. Y4 i" F* S) g q5 r
- Task.Run(() =>& x' f" l1 w& \/ f" z
- {
: A+ f( j/ {* \! g% D" ]4 v - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
) H: }7 j# N4 P2 O- h1 n" Q - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());; S1 B% _. L* F2 x) h! ~& z
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息% X: F" ^, |$ j. `
- });
) \1 X: C7 c2 v( ` - }) s( w& J6 I S: h- R3 f
- }: u6 s& T E/ ^. L% W/ H9 h
- catch (Exception exs)2 l1 W- m. n: p& ~7 U. \6 C
- {6 \: |3 b- D$ [4 U
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
. ^2 }2 o, T6 d L) Y - }) L* O g: B$ J0 ^, }
- #endregion
( }8 H& d$ ^/ c - }: a% _% C7 W+ O* a
- else( y1 C5 V6 h$ r
- {3 f* x) M' \: S" g4 E- ~
- break;* j# X8 l& m- j: R O
- }
# G: q& |8 L$ ^6 ? - }//while end
/ o' G) S! [8 h4 k; \- b9 }8 z/ e - }
7 B Y& J; c3 r E+ W - catch (Exception ex)
. W, c" @* _# t- A \ - {1 w$ s! Q2 M d
- //整体异常处理
( a3 v* {. M2 n, j0 q5 S6 u - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
N5 v) w0 t0 t- j1 f4 s - }8 ?6 h' i" H, \; ~+ I
- }! n" _& e! }4 `/ j% i
; y/ i1 ]! L1 x* w1 N- T- / u1 }7 J" W) P' J1 {' a* S
- public bool IsReusable
8 f& ]. Y1 \$ y; Q) D6 f0 X# z - {2 ~5 j* L$ i) l& t0 U" g$ h
- get
3 ]. W$ Y, A2 ~% {3 J+ A - {
8 C& B( o, P' [4 s. G1 o - return false;
9 M$ G' W. \" P( u, j+ G; l - }; h: B3 \( J+ l# S0 `* Q/ r$ p
- }
( J& Y' z, C: `8 i; q - }$ x" X; i3 q1 \* l
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
6 c1 _! i' e0 W6 x5 Z* } |