服务器端代码编写 1.新建一个ASP.net Web MVC5项目 ; N3 c+ y6 g$ K t" \
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
+ j( G! M8 B+ m3 t - using System.Collections.Generic;
4 E \! }, Y" S' j# i8 M - using System.Linq;/ R7 } g. d9 z) r3 W9 A' Q9 k
- using System.Net.WebSockets;
* U9 c) Y9 }/ Y% `9 F+ O8 d - using System.Text;
7 I, U% j- { M0 E - using System.Threading;
- T( I" k! I) V( Q( q& w$ p6 @ - using System.Threading.Tasks;
5 t& q: A/ V" Y4 m4 d* S+ |; B - using System.Web; o0 C( s# ?) _ J
- using System.Web.WebSockets;( u, ~2 h( h% ~1 n$ B
- 2 v: F% k$ T% F/ g2 o
" u+ p0 o4 }& @" V( ^- namespace WebApplicationWebsocketHandler3 C, P. J3 m6 Y7 e
- {, `( M+ L l4 `
- /// <summary>
% p4 v D! J- l0 o- _ - /// 离线消息+ E4 B. o. h- V8 A2 u2 l
- /// </summary>, A# X* r) J/ _
- public class MessageInfo* y5 h0 V k* V5 A; @
- { y0 H/ [* E# G) N1 [# A! n
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)4 j" r/ }4 T1 p4 `
- {
( r E% c( X9 \4 S$ w% F% n5 ^ - MsgTime = _MsgTime;
$ W, e0 M) d, b& y3 R$ h+ r& U - MsgContent = _MsgContent;
8 k" M( l9 `+ W& [/ ]. A) E& G$ S - }" Z0 r/ b+ q6 R! P. x# _- M
- public DateTime MsgTime { get; set; }
; m0 A0 k. Q6 B, {$ Q - public ArraySegment<byte> MsgContent { get; set; }& u0 J G) `1 Y+ @
- }
4 z: {4 @4 p& n/ N4 y - - |6 ^' l' W9 b, S6 r$ t0 U+ ]
- ' L% r' X$ l- Y D( f: Z1 q. q
' S- |3 H" |, Z7 c5 G3 I. @
6 a5 f" H+ |/ C- /// <summary>8 d0 @4 A; T) F3 N* v# S' i$ s
- /// Handler1 的摘要说明+ \0 x& \2 X9 l
- /// </summary>
5 p7 l/ T A* x4 b' y3 u. p - public class Handler1 : IHttpHandler
3 A, [$ V: ^) N) V3 Z4 W# h- k4 y - {& l2 {) M+ g$ L6 ^4 K& f
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池 l) P0 C$ V0 q T% v1 w
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
Y1 z& b* |% P0 L# Y4 k: a - public void ProcessRequest(HttpContext context)
% G% A" L% y$ ]% @, u% K4 o8 X. i8 S - {) F- E3 _/ \$ a# W- K K' K
- //context.Response.ContentType = "text/plain";9 r- X& U( [+ q4 H; _( \
- //context.Response.Write("Hello World");( U# U5 a) b2 \* w: F0 U! a- s. V0 p; S
- if (context.IsWebSocketRequest)
; X, u" p7 Q( { - {
: V5 w' z f8 Z - context.AcceptWebSocketRequest(ProcessChat);! t8 T' z# u) m
- }
8 S7 R* u0 [6 u- H4 I - }+ ^( t% j' _$ y V
- w1 I" V0 V% _- private async Task ProcessChat(AspNetWebSocketContext context)7 B" n( F2 J, [& c' Q/ h- a
- {7 j# {1 v6 ]: y* B# K- R
- WebSocket socket = context.WebSocket;
5 q. S9 L+ U% r7 `4 S - string user = context.QueryString["user"].ToString();
: ^, T( i6 ^2 U- Q9 B( m7 } - " h$ ~6 ], h' e. C3 l+ p
- try( H% j# z: y! Y8 w/ G" G
- {
* k2 d" ]( ~, X3 j7 I3 {& o - #region 用户添加连接池
- s3 Y$ D0 s7 z1 N, d7 T - //第一次open时,添加到连接池中# U" W5 a) d7 x Z
- if (!CONNECT_POOL.ContainsKey(user))
" @8 N. K" C) J$ b: M- E/ V - CONNECT_POOL.Add(user, socket);//不存在,添加) N1 b- u3 [, O
- else# j+ ~+ K4 y3 F4 u
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
: e2 E; U7 r+ t% Q' n3 Q) ]8 c - CONNECT_POOL[user] = socket;" C6 l: i1 U! n
- #endregion
" y- A) k% j7 f6 ~6 Z+ d* B/ c - ) m4 r* Y) J; `1 ?' [$ v( \
- #region 离线消息处理1 z& }# f' D0 i
- if (MESSAGE_POOL.ContainsKey(user))( P7 x6 K0 @7 i6 t' j
- {
$ u, q7 i* H. t - List<MessageInfo> msgs = MESSAGE_POOL[user];5 O% z) _3 X0 l9 n
- foreach (MessageInfo item in msgs)% P) y4 V9 l" l+ V2 x
- {
+ L" y# P0 \0 D! x3 y) b! H- C - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);/ I1 \9 \) ]7 d% K% s
- }' O0 N# a0 c8 U8 ~# e
- MESSAGE_POOL.Remove(user);//移除离线消息
) L! y3 N4 j! h% u2 T; G - }( A% t+ L% c9 ~ R
- #endregion
9 _* P- H4 k) F8 A' }9 E - / t9 |, A0 L |1 P/ ?) P8 }
- string descUser = string.Empty;//目的用户
% \) q, h8 @4 q - while (true) L8 P: i! B* h1 S! q& w, Z! J
- {
) r* p: {. c# N. l; n! K - if (socket.State == WebSocketState.Open)) Y# m; m M. R' H Q
- {
) V# p( i- k) t - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);! \9 x( q* ?0 L8 E, T) Q8 n
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);( E: ]- w; c/ h% H. I) e$ D' o
- ' S9 w! S! D. v1 I
- #region 消息处理(字符截取、消息转发)
. S, e) N# `1 O, _ - try' g* y6 g( e; l7 q% f4 S9 d! g
- {
7 J' g/ \( b; E8 e2 U4 S - #region 关闭Socket处理,删除连接池
$ y" s6 K! }. j+ |% s% r: d - if (socket.State != WebSocketState.Open)//连接关闭
1 c# x* A W! A! Y( o3 V; M' _ - {
1 C% @* ]# _# p% c& } - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
" I3 u* M( i: E" O - break;
5 c$ y+ O7 P$ Z2 f; ~ - }
: C) `0 t7 n& R4 ?+ b7 R - #endregion
* B* ^! F: G6 Y3 Z7 s, N& M
+ ]9 W' G' I4 d! X8 m0 a- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息5 l, h( f' B0 Y E+ I; T+ Y
- string[] msgList = userMsg.Split('|');( C& `2 t& w( b; c2 k; q
- if (msgList.Length == 2)
& | o9 E- I3 v0 m+ m4 \, c+ f - {' i t( W% |9 B5 o
- if (msgList[0].Trim().Length > 0)
0 p5 [3 B u2 F4 r# N3 e - descUser = msgList[0].Trim();//记录消息目的用户3 @1 ?& `8 q/ I! T/ \( C. b" _
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));7 v. X: Y S# F! M8 `
- }
; |5 e+ f8 |- d - else# M) N& C2 W H" U& N2 ~
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));2 z0 Z$ o2 l" F9 H
/ c8 U/ F6 E; p- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
, u; F$ a* J. ]8 L9 j1 b! L - {0 p l' F+ n" k4 G( s; a
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端- x5 [1 L, l5 E3 b1 W$ P0 ?, b
- if (destSocket != null && destSocket.State == WebSocketState.Open)9 n$ l9 Y& p1 L
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
; h8 `1 z8 g3 v5 L4 o - }1 v& ]$ X* h* m9 q& o7 N$ q
- else
/ T4 M8 e2 ^' W1 ^% Z: t O5 U - {
5 ~& K9 W/ z0 @$ R/ K - Task.Run(() =>+ k, F8 h) V3 O+ D P
- {
) n& k" l( @; y4 g) h2 M - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中6 z- |( Q9 p- b; B- D' Q. r1 F1 B
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());; ~1 ` h3 Q, p- q( r% H
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
- B! M: k8 ~ { D! Q6 V4 a% w - });3 [4 d# J* ?" m5 b6 o1 ~
- }9 G1 {3 b# p" Z5 H& y: X
- }
# `) T5 O- |1 \; ?" y! k - catch (Exception exs)
- S. P8 ?+ D+ S( x+ T+ M" U. w4 m - { ]7 o+ j& a) m, P3 h
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息4 }& a$ P$ x: q
- }: Y- {& r3 V l( C
- #endregion
. C: ~, Y, h- U# e - }
" U* E8 a! s$ c; ?" q2 K% E - else
5 q) k" | u4 F* }4 L/ v# { - {
7 Q& R. S8 M9 ~+ n! Y) l3 N - break;, U5 h9 x8 i2 A! S
- }
3 \5 B; o- z' E# u - }//while end
/ q5 A+ f! ~8 w! c$ a - }4 [$ M" M0 e8 y) B
- catch (Exception ex): k9 X0 x: J s2 e- G
- {( C0 l) G$ }4 H: _! y1 M
- //整体异常处理1 J* e+ N$ t7 ~7 P3 t5 r2 ?+ c' m
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
6 G- O3 i- R: V s b& i' f' e# k - }
( |7 E+ p+ T0 { i( y' j5 F. C - }
6 D! H8 z2 q1 M - 5 j! {& W/ w# R8 x5 Z4 J
- c$ y2 ]& P! J1 u7 w- public bool IsReusable
) j& ^$ j# l+ K. U- D! S& u - {3 d8 \/ J; Z- |, p+ }
- get( D$ A% Y2 G4 C2 n. \5 {+ @0 F1 A
- {# k |; X! L* d3 R1 U
- return false;
' V, _* j: W0 ~) P: E9 ^% C - }7 ^3 [( T6 f* g1 G) A4 K- w1 p
- }
. @" L" M& M4 Z( k( v - }% y2 @6 i- b. \/ k, S
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
* c. g V) M% b0 R" h* [ |