服务器端代码编写 1.新建一个ASP.net Web MVC5项目 0 |; T( Z8 f# B! @
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
, O. n* A3 k! D3 C6 n' Y) p1 y - using System.Collections.Generic;
, K% H/ t$ v8 I3 V4 z' S/ a) \1 b+ { - using System.Linq;8 N. G2 o4 x# U& V( W. u
- using System.Net.WebSockets;
& Z, x4 _3 v& d: o3 L# O) b - using System.Text;5 w/ l8 K. L, o1 {3 m# }! d
- using System.Threading;- r8 O% K, W; ~4 O8 S/ ^
- using System.Threading.Tasks;- o+ }) ~( p7 j8 c
- using System.Web;
6 v8 U: T' K) E/ @! b, |/ m - using System.Web.WebSockets;0 ^& g9 R7 N) i, s# {
- $ {+ T( T2 B4 h( o; O9 f
: [/ q- c* D( q! D% v z- A- namespace WebApplicationWebsocketHandler
/ Y4 A( y* H3 D5 M1 B - {" h& \: _8 A4 d. M8 N$ U# D, z
- /// <summary>
2 H; v# }2 S. f9 F; z- a - /// 离线消息& ~8 j# {* ]8 V9 d
- /// </summary>
2 h+ p* e3 P/ J! M: Y - public class MessageInfo) Y: v2 C5 }4 h8 X9 _9 @
- {- |1 B; H* `8 I
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)' Y+ v5 ~5 @" x
- {5 N- ^0 b" f3 k0 y* i
- MsgTime = _MsgTime;7 c9 s& W6 q" r B5 O
- MsgContent = _MsgContent;
, q9 X1 L) h1 q - }
8 l! _" @- t/ r Q/ m, J - public DateTime MsgTime { get; set; }
# A1 l- E) A7 c' j! _ - public ArraySegment<byte> MsgContent { get; set; }* ?8 @. F' ]2 e; J# F2 I
- }' j0 X P9 w% V, Q
- ! Z' K* w+ ]8 s# w2 ^/ \/ e5 ?; s
% d# Z- q$ e* O; K
3 w2 o5 I6 ?! W- ' Y9 j" |# ]% t; z: |3 h
- /// <summary>
% N# b' r! z- L2 d - /// Handler1 的摘要说明% w& G! U& g4 V1 {
- /// </summary>
0 M/ L8 S( _, Q I - public class Handler1 : IHttpHandler
- i# @3 O8 S0 N" d0 a0 Q1 ^. A - {- P4 `6 C6 W0 ~0 [9 ~
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
( Y1 a3 R% O/ o- v: i - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
, f8 j5 y: e# _! w) C4 x; p - public void ProcessRequest(HttpContext context)" S- T4 P3 X6 {# h8 e
- {* d0 w: T" p& Z f8 f* l
- //context.Response.ContentType = "text/plain";
* ~/ a; r/ X- I( d9 P. e. e - //context.Response.Write("Hello World");0 m7 l7 X1 [% p( }/ p5 K
- if (context.IsWebSocketRequest)
T1 ?- X9 u3 }+ Q - {
. J/ \# {1 e4 v$ m$ m# F - context.AcceptWebSocketRequest(ProcessChat);
! g9 G" }( n* {% t$ C - }
, I. P$ l G+ b - }
5 `, x( A6 m! ?- ?4 p0 r2 {
+ u! F, b2 S/ K( k* A1 `& a& J- private async Task ProcessChat(AspNetWebSocketContext context)
9 f7 c0 `; X, r9 v( @ - {
* u0 K8 R) e# l0 B - WebSocket socket = context.WebSocket;9 J4 c8 B$ d/ h9 t- a' h% q
- string user = context.QueryString["user"].ToString();
: S1 l; t5 s3 F8 a" F
# r, {- F& O+ f0 W- try
* y9 I6 ?3 R9 v+ K2 N) G& C5 I+ _' d - {6 o$ m. l' J+ Q$ z. Z4 d3 D9 {
- #region 用户添加连接池& l* ?4 H$ M! |( a! s6 D% `6 p# M
- //第一次open时,添加到连接池中# b( K [9 A `
- if (!CONNECT_POOL.ContainsKey(user))
" v* L- g4 j' w7 Q+ w9 g: C+ X I - CONNECT_POOL.Add(user, socket);//不存在,添加* } y" t' v+ K5 f8 k# K: `
- else, m# G! m! b) q- g
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
; Q! t; r N# e' Y - CONNECT_POOL[user] = socket;
3 |8 j/ H" W. o3 S) Q8 N - #endregion' f$ Z: b6 m7 B+ n5 F$ ?$ m! `
' H4 c1 M, T/ x( k: G' [- ^- #region 离线消息处理1 `. a/ X5 {7 t: w& D. w8 g" e
- if (MESSAGE_POOL.ContainsKey(user))/ Q1 S0 F2 q. l( ?0 h
- {
! O0 X1 e6 g; z0 U( D- P/ p - List<MessageInfo> msgs = MESSAGE_POOL[user];
9 [ M' X3 u/ h' G - foreach (MessageInfo item in msgs)( ^- F% Z+ \6 I' K. a
- {
5 D0 }. d4 w! z; x9 S) h/ e; ?, S - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
, [$ X9 C' Y4 F/ G% | - }* ]. T' t/ n' E
- MESSAGE_POOL.Remove(user);//移除离线消息
# U$ k O' P0 B# J. I - }/ V" `* _2 K7 t: z3 j$ K6 o
- #endregion9 }. ^( v8 {! R" @7 U1 c; R
7 z* [/ _8 @# g1 V. A; p% d- string descUser = string.Empty;//目的用户) p1 x9 u6 n) \/ H2 W0 \
- while (true)+ ^3 _ x1 }" ?1 y7 Z
- {
4 {. `$ Z+ q. f, c b) E; i4 h) | - if (socket.State == WebSocketState.Open)( U% u. y8 y4 k% c6 Y, m
- {
( J0 C. k( K( g- ]; F+ Y# e - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);/ l! S% O3 L. Q) y4 k* ?' C
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);$ F4 B+ B' G! a+ u$ Y- L
- + [& D" F' B5 L. H/ y7 W- x0 H3 L
- #region 消息处理(字符截取、消息转发)' f# o' j' X+ R* Z0 U: w+ c
- try
' Y8 M3 h; O# B- g6 k - {
& L& u8 y$ Z: x7 ~8 Y* S - #region 关闭Socket处理,删除连接池: J+ G: v, n3 Y; \& Q; |
- if (socket.State != WebSocketState.Open)//连接关闭
2 E8 h$ \5 p& U5 U7 v: Z% R/ g. o - {* y, ]) `2 K# z7 t5 k
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
+ W% P/ j* @0 N, Q - break;
5 b! O% z- ~$ Q% e% m% z - }' l. h/ O& l8 a3 }2 \9 m% j
- #endregion4 C, l& N; S/ X! {: y
3 i( z. t* s/ D# D4 m" d+ L! e- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息' x5 v2 f, j1 O
- string[] msgList = userMsg.Split('|');4 {' e6 E% {' G7 g' Q' |
- if (msgList.Length == 2)
' j( P5 g2 k [ q9 t& I9 W - {
4 m) N5 l9 S& t4 i P - if (msgList[0].Trim().Length > 0)) M, M- O# G/ K, Q
- descUser = msgList[0].Trim();//记录消息目的用户& `" T, o& m$ H! y) X1 Y
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
; g9 k/ A' v9 i2 ] - }
( x/ o6 S" B" b7 f - else& ^0 S: i2 E. e6 e8 ]; Z. z
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));2 E+ o- ?4 |$ \& u
- 5 x F$ f) E4 k
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
- P+ H* o; ]: [ - {' S* G: \/ n% Z, U1 ?, e' \
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端0 m7 x1 m7 c! Q( j- ^0 W% R
- if (destSocket != null && destSocket.State == WebSocketState.Open)
! n# l+ T5 E1 Z2 x8 i$ S - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
0 Z. y* q& s" T1 Y( D - }5 @+ d( z0 w( e. R/ I: ?: J
- else
# a1 w# r) w& \+ j) ? - {* u; E7 Z8 j2 M0 r
- Task.Run(() =>* V( z$ p! k# g: q. u) L5 G7 S% J
- { G# x( I) t! U- x9 x
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
4 l% g/ G ~! J3 o! } - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
7 {! x( t6 v/ C. N& n - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息$ T7 n/ g- \- ]; d% c
- });
$ \' E+ O ~4 r9 ] - }0 J- W( O" h) ?! t
- }& g# K3 P! P! J; `
- catch (Exception exs): n, s2 k$ @9 s! q% K
- {
$ d4 n: ]/ G, [; @% S0 E& c8 w - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
$ [7 h: @+ D6 j7 F - }% A4 a' e# T7 |3 D7 D" d1 V; C" Y
- #endregion5 [3 _6 Y3 n6 q6 O$ g
- }4 Y" {- O! r! ^8 | ?# @/ `
- else
! f, H# @. W* M8 v% V+ g# Q - {6 w" p" f5 y, ^* t5 S5 j
- break;
7 o9 ~9 o" w3 n$ y9 o - }* h& K1 M$ V$ |
- }//while end$ i- J5 a6 [$ H
- }9 F4 b( J- j5 ]0 V/ ~2 q
- catch (Exception ex): u$ ^% z: k1 ^0 Q/ Q3 r* @
- {
1 f1 s' b6 c# b% a, ~9 Y - //整体异常处理
, s* j. Y% y9 v( }# p4 i$ y/ ?, G - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);0 Y3 l) W3 Z. u0 ?# T+ j
- }
: j. ] N5 J0 \, f - }
: g6 d$ N# V; O- Y0 ?0 S. U
2 U; {3 U( P9 ?2 O5 d- 1 [* v4 O8 b/ s9 x5 y, t6 I
- public bool IsReusable k) `# D' [# T6 _
- {$ q0 @$ l, e" v0 J; k" N5 ^
- get" w4 g ^1 y! Z: b' ~
- {
" c1 O) A& I% q. P8 G9 D - return false;
/ f i! ^6 n8 A& e% G) G) d - }$ ^, i$ [ F9 x9 @! u& K2 z' [/ D
- }
# P! O" {' w3 q8 L; n& ` - }( D# {. ^. G0 i+ r* T4 F
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
r4 g! [* E) c4 E |