服务器端代码编写 1.新建一个ASP.net Web MVC5项目 : e3 Z& j5 _& k% a4 |; V" p/ }" Z
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;; A* Y5 [6 S, U5 s0 E
- using System.Collections.Generic;5 g7 n. V( l- O6 T) c6 V
- using System.Linq;
% E0 z- N5 R* e& Q& N; t - using System.Net.WebSockets;3 _4 H% z2 ^# e4 Z9 g. U
- using System.Text;/ p" l Z# U/ L
- using System.Threading;" @& u2 x$ a. [& ^5 N5 Z* E# m4 w
- using System.Threading.Tasks;
& Z d# ], d8 W+ B/ d% V - using System.Web;! y( M# F/ V4 u
- using System.Web.WebSockets;
$ B' V; Y* e2 @: L: B - 0 y- ]1 t9 f$ N; | j6 F1 R, T# q+ a; f
- 1 P3 e! C2 }, v
- namespace WebApplicationWebsocketHandler
) O" e u: R) V$ v# |8 h, h, }% G5 N - {2 `: {' Y8 L/ N$ _# B
- /// <summary>/ n; u; y8 j4 R, S; e: l' I
- /// 离线消息
, |! q* a. I0 G% _3 [) @4 Y, x; g - /// </summary>
8 v* L9 x" H% h5 O( j - public class MessageInfo# q5 u7 L: |# C( h
- {0 u+ v2 c9 T+ j9 s3 U. F% n$ s R
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
( w9 c$ [: Q4 h& C/ c7 o ~ - { r$ v6 ]) }" H5 y8 D
- MsgTime = _MsgTime;
3 y. M8 _' ]0 y: Q0 p Y - MsgContent = _MsgContent;
5 R& t J! A6 a; d# Q3 F) ^ j6 F: ` - }% V5 e; D# P& O3 c4 g' {3 U7 F
- public DateTime MsgTime { get; set; }
, n9 B) ~7 B+ y' `2 z! } - public ArraySegment<byte> MsgContent { get; set; }$ z9 }3 e0 k l9 H' O% I
- }
4 |; d" G. r, q6 Q) j' f, A - * M6 |3 |- x! s3 E( r O/ m8 }% D
- ! v# U! Q9 `5 O2 q5 `* X
- + c; P; s8 g4 _- C
& D: m @7 S" z- J5 O; T! {7 w- /// <summary>, H/ `; h8 o& G$ F9 e( \: d0 ~. R
- /// Handler1 的摘要说明
9 }+ _. g# m5 w" J7 J z! _ - /// </summary>
& w% S% z9 E) Q" D% g - public class Handler1 : IHttpHandler9 a0 I7 E$ G! c: O$ K; R$ X
- {, P. m, r, s- z, V
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池- P- U1 C/ p1 \1 f
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池$ i% m- R: M- @" F. C
- public void ProcessRequest(HttpContext context)
5 B2 R) M7 F0 H: X4 G. r% y - {
?) z. F) O/ P5 ~ - //context.Response.ContentType = "text/plain";
e) }# u4 f* f X0 _$ }0 v; k - //context.Response.Write("Hello World");$ g4 @* r( ]; z4 H2 A6 U: p- J
- if (context.IsWebSocketRequest)" u, |2 K' H, _7 X+ H1 |7 w' c
- {
6 l) H* w! ?" H0 q, M+ J$ U - context.AcceptWebSocketRequest(ProcessChat);
1 z* g" Y: O) x - }
" R7 i/ W6 o+ P - } t* k F! ^7 E) z& O- b8 h% b
- ' n! C G* Y3 @2 u: r( u4 I
- private async Task ProcessChat(AspNetWebSocketContext context)7 }5 A6 g* y1 F) _& h
- { d9 V0 Y" z* g# l0 R
- WebSocket socket = context.WebSocket;
5 @& M+ ]0 O8 G/ w5 ?4 U - string user = context.QueryString["user"].ToString();
7 |: D3 [5 E; i3 R( ^ - $ g" l2 A! Z0 `) I v
- try
* K5 V% `: m% b, C - {3 @% l( ?0 h- |! L) m
- #region 用户添加连接池
# K: R; X a6 z# Z6 @( b$ S% k - //第一次open时,添加到连接池中
# P# u1 D; Y" S7 s( Z/ r% M4 n2 I - if (!CONNECT_POOL.ContainsKey(user))
' o- ^$ y' y4 f( q$ O' G& N - CONNECT_POOL.Add(user, socket);//不存在,添加
6 T3 ^9 e% A# R& i - else' G* [5 u, T# f2 U; L2 H
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新- n0 H4 d( O6 q& ^5 v0 x' a1 }
- CONNECT_POOL[user] = socket;' r* G7 `+ @! q! J1 e
- #endregion+ P, l# r7 U; F
) \8 W ]7 t6 X* I: p" f' L8 g! Z- #region 离线消息处理- k* s$ T+ {+ s7 U5 F- q+ ]0 l0 ]7 U* U
- if (MESSAGE_POOL.ContainsKey(user))/ @1 W2 |" H* t" L) _+ L' n
- {
& G' W2 \" k7 L6 I3 t - List<MessageInfo> msgs = MESSAGE_POOL[user];# }8 [' B( F# _) K
- foreach (MessageInfo item in msgs)
) d' g& E$ P& c) _8 {+ c - {
! }7 |; ] s- V3 k2 w7 g" ^" m9 N - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);1 f9 R6 W% y6 }7 t
- }" D" U$ c6 L% M0 d0 q% Z
- MESSAGE_POOL.Remove(user);//移除离线消息* Q3 i/ c" ~' v$ Z& _1 W. }7 ^
- }
0 e0 c A N2 g - #endregion# r+ _- }! G1 f y0 j2 g/ C. _, v
$ H5 Z/ M. F* a) s7 O- string descUser = string.Empty;//目的用户# f) ]. @0 ] ~$ i8 g
- while (true)
- H: C C8 E' \, L - {
; T; A" }0 t! Y - if (socket.State == WebSocketState.Open)2 H% P0 {# D; ~8 n$ z5 H2 ^
- {
+ L, a/ n$ Z4 j' U* f - ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
/ z2 ?; F3 R2 R& A. n/ w - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
; [9 j, Y* {/ y3 }( Z: n. h6 r9 ] - * u# `1 t, Q# U7 n \: d
- #region 消息处理(字符截取、消息转发)" Y; d B/ S) B- Y5 ]
- try {3 a. k8 r: T) Q1 X: j* R
- {
: ^3 I- y( y& ?% ?* l) x6 O4 w - #region 关闭Socket处理,删除连接池
5 e% o$ y( a% \- i& Z# h - if (socket.State != WebSocketState.Open)//连接关闭
& `8 q5 f& ?5 C# a( _ - {
/ r7 k/ ?6 F" ^- n, l - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池# Z' J" P. X0 @5 ~+ i
- break;, g3 v* z0 @ o: I. c P
- }
$ @9 C/ V! k* C0 w- B - #endregion
2 D+ O8 Q& l' I: Q* T/ u$ R/ v - : l. A( s! a7 C" W" s* m! I3 e
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
" Q, K0 y5 D$ e! i/ h2 |# p$ e j - string[] msgList = userMsg.Split('|');) N! C4 |* J) \0 K7 A4 M* S
- if (msgList.Length == 2)- I+ C9 p: S6 \# G; k7 @: u
- {9 s3 [5 ~0 ^- F
- if (msgList[0].Trim().Length > 0)
8 x! {6 O% ^; o - descUser = msgList[0].Trim();//记录消息目的用户
! `2 s0 q% u. S1 P, M - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
" c8 `1 @1 r# [9 C) r+ {9 v - }
6 A) M* t; _; l/ Z6 j$ C - else: b. g0 Y2 G, D5 V0 i" V
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));4 f+ _& J7 {1 E' \6 Q8 f
- 6 p+ Z( d8 Q7 t- E4 ^" L$ `5 C$ V
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
2 c- D* t) s% k) K8 V - {
7 t c1 E1 o7 v4 a4 P - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端4 t% S3 E& r( Z& L) }/ Q- J
- if (destSocket != null && destSocket.State == WebSocketState.Open)) N: J; X/ `; C2 W
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);7 F) M% o2 ?9 e1 Q s4 }+ Z& f! _
- }) l& v. }3 B' x# h: R
- else
6 e* q" C; T5 g - {
' s' _$ R- ]' J - Task.Run(() =>2 l+ n! O v' k
- {2 v: k( q% _+ K% M
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
( Y7 O; q9 C' w" _* { - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());1 e4 \8 X: E0 [
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
4 f- k$ S, K5 I! k+ ] - });& }( {4 Y9 `0 T [4 H2 w
- }
' I) |0 O# U4 N r3 Z7 Q* v$ {! E! o - }
5 [' D. _' K: b# `' { - catch (Exception exs)
* O) X; x' b) @' b - {9 [% O0 y: k5 c) N3 [* p
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息# _: Y3 x+ ~7 G' M& P+ H$ B) `
- }
3 w3 J/ n3 d7 y! V* |8 s. \3 | - #endregion
& T" ^ s. c; P# w+ a, {# E - }
1 P _; b( d n6 } - else
; S" R& W6 `) A) k- p! f - {6 u k. y9 G5 t& x
- break;0 S: ^' Q! c/ Q$ S& c$ C% w
- }0 h5 L' v2 O5 |5 }0 G* o) Q
- }//while end9 t6 H, D5 s& ?- {, c
- }$ e' c O4 q# L C$ z6 _2 W
- catch (Exception ex)
5 [6 j) r- @1 i7 a. B8 P/ p - {
9 E( v# z9 [4 K; T- S - //整体异常处理
! J7 Y# d; c: h ^- @+ U& g+ ] - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);, |; W$ u! g0 P9 S
- }# r2 Z) z" j2 j) T
- }+ K g" H; p& `. P
- # s- W& i0 D4 X: B3 A Q# F
( o4 r! r' b4 ~- public bool IsReusable, `% Z/ s6 F6 ?* Y, j' B1 M( b# a
- {
/ ? E C) P; ~. Q - get0 n) g) B5 q/ B9 j+ m9 W8 C
- {
# f) k! \) J1 r - return false;4 q9 k0 |( m5 u# `2 D: s
- }' f/ O: ^& T& c- `1 w% H' E
- }
# \; a* f" K& a+ @ q, K - }
$ I% P$ w; O% _3 B - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
\7 o: v/ E3 z/ i) L& @: R( w4 ` |