服务器端代码编写 1.新建一个ASP.net Web MVC5项目
; |/ i7 ?- m( f+ P- R- E2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
3 n3 G4 V5 D9 s! z: k - using System.Collections.Generic;
- R* w) M% w, e - using System.Linq;
' m0 t/ ~+ C4 k& U - using System.Net.WebSockets;; v: D* g% a/ u* p0 {* v
- using System.Text;) H( M" C4 ]! x1 K9 Y
- using System.Threading;
( @% ^, q1 t" u' g% u - using System.Threading.Tasks;7 j; O* t+ k0 C1 {% k
- using System.Web;9 X5 d2 m9 j7 v
- using System.Web.WebSockets;
1 ? W0 i, W: ` ?- p' _
( b0 d! O \6 a6 t2 B- [; s7 b- 0 G& V; D. \2 G) \- C2 r7 B
- namespace WebApplicationWebsocketHandler3 r1 T8 I; [, X& ^6 z+ L3 X& a) V: \0 V
- {7 Z& a2 z! v1 u" w0 V; h6 M
- /// <summary>; f2 p7 N& d: w5 H/ | G
- /// 离线消息
. k ]2 a& D6 g e( c - /// </summary>
0 R7 T- v3 I4 M, d0 U: p C8 k - public class MessageInfo
% q$ d$ }7 m$ p, |. t - {
, D: `2 D" I. ~2 W* m8 O2 i, T - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)3 J% D2 m4 J; ?0 L# y( i0 M8 [
- {
9 T X4 V5 q! x9 o9 ]! e$ P - MsgTime = _MsgTime;$ k, F* ~7 s9 d+ y4 k
- MsgContent = _MsgContent;. Q7 j7 b5 y3 |
- }
) u. V) w, F& u Z& z8 W" F - public DateTime MsgTime { get; set; }9 H9 f2 u! T0 d8 S( Y/ \
- public ArraySegment<byte> MsgContent { get; set; }
3 n3 u1 K$ y- f, t# z) q3 J - }& Y6 r. @. ^6 I
6 q! P8 z5 s7 j; L
: J+ r( ^) [0 U
% d7 a) C9 C. j9 X- 0 u- y! N- v/ x; W9 `: Y
- /// <summary>1 X% a. m* f" G7 m, o7 W
- /// Handler1 的摘要说明) f& v2 C* H/ }9 j0 d# B
- /// </summary>* ~4 w$ D2 o/ F: j) ?5 ~
- public class Handler1 : IHttpHandler- d8 i1 ?/ u1 w4 j' L1 h8 W; O3 B
- {
& g; G% r# l" D$ ^0 K* e - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池) R' X/ f4 Z' V+ T% W
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池$ u8 Q* L' J7 \
- public void ProcessRequest(HttpContext context)
' Z8 o, r! O* s5 r. r. u. A& B - {' ^$ z( t8 `. c
- //context.Response.ContentType = "text/plain";
% B7 Y! I, Z) S: s. {9 { - //context.Response.Write("Hello World");
& V v$ X; S% u( s4 _; g; u, F. S0 b - if (context.IsWebSocketRequest)
) r$ y/ `5 x, C$ M - {
9 t2 h2 U- p9 x5 ^4 Y/ y5 n9 o& A3 q. O) C - context.AcceptWebSocketRequest(ProcessChat);
" _0 Z) b+ z6 C4 F" B9 O - }
3 N2 e$ Z* P' u - }: F* ?1 J# X) N/ @8 D
6 U) h& K. l8 k( s- private async Task ProcessChat(AspNetWebSocketContext context)& Z1 b4 v# s# k W$ Q* a
- {
; p( U) R3 y+ }5 H' z" p; Z y( t - WebSocket socket = context.WebSocket; G7 P/ J1 Y+ O# c/ G( J- k7 ]
- string user = context.QueryString["user"].ToString();4 j, H. V) p" ?# b$ n$ x9 S, l9 h
' s7 ^7 } G: q% ^# ~' x4 i- try
8 ?8 V# j. O. Z+ ?# O) ^: E - {
+ \: K2 d$ B. q6 ^6 a0 e - #region 用户添加连接池
+ X; h) V e# ?3 a0 A$ Z. ^ ?3 g - //第一次open时,添加到连接池中2 r2 n; n, e5 p/ `
- if (!CONNECT_POOL.ContainsKey(user))
. q* _8 R- Z' K2 x5 n B3 } - CONNECT_POOL.Add(user, socket);//不存在,添加
# l& f1 m! J0 z, h8 v5 Y R1 T" T% y - else1 ? {$ Q; E1 V" e E- E
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新5 `9 S. @) D1 O" J2 e
- CONNECT_POOL[user] = socket;. I Z8 z- w3 J
- #endregion" W u9 d! ~ G4 |6 @+ m8 @
) d! J# K7 g3 m* H7 w, c, |- #region 离线消息处理" x! h8 N- X$ Y
- if (MESSAGE_POOL.ContainsKey(user))* K! K! }$ {- i ^( B& T) _5 O/ N
- {6 Q6 q0 e0 d! c
- List<MessageInfo> msgs = MESSAGE_POOL[user];
4 A1 t0 L9 R/ |( F; N - foreach (MessageInfo item in msgs)
1 E+ r- \4 x4 T1 _ - {4 l2 l Y9 g: [* j! V. n
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);3 f# U* `' N" p
- }& r+ K2 r( |0 t6 h) [- N6 S
- MESSAGE_POOL.Remove(user);//移除离线消息
! i; c1 q4 w7 {: Q0 b - }: }0 G7 p$ _) ^9 X! e! O: U, O
- #endregion
- G$ M7 G5 a* h
; g* Z6 f# [( d7 \3 @- h$ d) I; v+ l- string descUser = string.Empty;//目的用户/ y* I$ r2 Y: \: v, L# k0 _& x
- while (true)& j: t+ f" {) C3 |$ Y
- {
2 P2 R7 H+ }( K2 V; e+ G" P; [ - if (socket.State == WebSocketState.Open)
5 C- A' Z# {0 Y - {$ X8 A, h2 J. R$ B( P' j, w
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
: u$ j, E( B$ y$ L - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
( f. s, e+ U2 g% }
% n3 r4 p" U2 o9 H: ]% A+ i- #region 消息处理(字符截取、消息转发)
2 _5 Q5 \% T1 x& _9 @( X# x9 M - try
# u1 i1 k4 ]* v - {' U# i$ Y! S% a+ F1 q$ J+ g
- #region 关闭Socket处理,删除连接池' m" z. W7 B1 q9 y" V/ u- |& J% d
- if (socket.State != WebSocketState.Open)//连接关闭
2 ?3 x: h0 n" {( d8 r ]/ d - {& H- X$ X* Q1 D8 I4 o& Y0 C
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
8 P+ \, w1 q* T - break;
9 C" E, I& R, k- x3 N: x9 `/ J0 ?$ _ - }4 o" |8 G# s4 m5 J5 ]
- #endregion+ f7 m6 ~: e# @4 e& \: H
- 6 M. u- ^ s4 }( ~
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
5 e5 Y, p3 b3 E) B - string[] msgList = userMsg.Split('|');2 C( Q C. C: E( v
- if (msgList.Length == 2)0 v l* ?( b2 g8 N2 _; o1 x* `
- {
/ ~1 J: b3 F: ` - if (msgList[0].Trim().Length > 0)) d9 I7 o9 R! _" ~) \% u& c1 c
- descUser = msgList[0].Trim();//记录消息目的用户# J5 k' ?6 e: M
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
6 W* \, O E' W. Q f; h - }0 S( N3 P) o) W2 i5 R5 H2 i! g, \
- else# {, b' ^+ ?0 ?" i3 L
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));# c4 f& J7 l6 x; i
- " v8 u/ j& z. K+ H; t
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
9 c# }" U4 y, i, e6 _6 I4 l8 A - {. K; \# [. G) ]$ ^ P
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
5 T0 }# x: q4 g3 N" N- ? - if (destSocket != null && destSocket.State == WebSocketState.Open)
) l6 x; \. s2 I/ b8 ^$ g- L( g6 c9 r - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
) a- a) L% f' j% j$ O2 i - }
- ~' q8 ^- R% e# q - else
* V$ {$ s( H. @4 J* e M6 g - {: O; _4 m4 ^1 y
- Task.Run(() =>! j3 D+ D, l% t- ~
- {6 a: f: G9 S3 d4 D+ `: f8 c) ^
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
7 x# h. w9 q' x - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
# B6 g+ g: y; m+ _ - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息) F& S0 p4 q) m _$ Y* `
- });3 e$ b7 K1 C) J) Q$ e: i
- }
, j9 q9 _& Y, p# [' T - }
, H7 b/ G8 `6 w% Z9 S. g4 ~ - catch (Exception exs)
& i$ ?4 d+ B& h - {2 {$ F6 z5 V8 I
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
. M4 I* p9 p7 L% M8 a - }
, Q% q, A, H" B - #endregion
, Y7 k; C, l$ R* x+ { - }
1 D, {$ w! N( s" T b - else* u( F) I- `" |$ r5 c, w: d' b
- {1 U# y! j4 a; P ~9 H. H
- break;
- Z% \1 N: c {) h4 [. ?- J - }
' `6 V3 H- @5 Y - }//while end
! ^# I. l( s+ r# Y2 m$ {, e( x8 @ - }! ^2 L, z, Y; B7 _1 l9 N
- catch (Exception ex)0 `9 C: T. ?3 b* P6 \. ?+ Y( i0 R' B
- {
" v' X# m' o6 K - //整体异常处理/ c6 _$ a% E% M, o8 `
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);7 f2 R* F* e6 |3 u$ E
- }
& M1 o% ]1 U/ O/ e/ L3 w/ e - }
: g! v% h$ ]8 b% ~! ? - " |6 R0 y' S* f
- 1 W, r, R/ O: y( Q h O
- public bool IsReusable" x/ }0 G" V1 H* z2 H
- {* }; _; ^6 S8 l8 r6 i
- get$ H9 n9 L8 M! d( K# }
- {
` ~" f, m4 Z4 R+ |1 U2 t+ k - return false;# D1 [8 e) M; {9 o* f6 Q
- }
" K# s! W% R ~) U2 Z2 U* N5 U - }
( D# p5 u: `. s4 e2 ]. }5 q5 p9 \ - }
, {! `3 a! v" b, u8 ?4 C - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 8 o( `* H, B' ?" U
|