服务器端代码编写 1.新建一个ASP.net Web MVC5项目
: Q/ f' H1 ]4 I2 W2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
/ w: s( D; N: D& `% H. z - using System.Collections.Generic;9 L0 x# R% X" P2 V6 O
- using System.Linq;
6 f) Y( y" z, q3 w# q - using System.Net.WebSockets;& G# [. s% {- i9 D7 P; U/ J
- using System.Text;
# C7 r" Q! m, E8 p! i+ j, I - using System.Threading;
' Z. o0 g/ I/ E4 D& \ - using System.Threading.Tasks;$ @; F9 W* m% Q) u
- using System.Web;1 A/ N, G* T( _5 A+ F, r3 P% z i
- using System.Web.WebSockets;8 P% J d: k) t0 e9 G
$ ]* u$ \/ t9 `1 \8 u3 W" I- & S' p P, F4 v
- namespace WebApplicationWebsocketHandler
X9 ]; Q: e8 Q0 t( S8 D! r/ Z5 ~& ` - {7 G1 d4 Z/ Y5 j5 n
- /// <summary>
* M$ a. W O: K% c: |! F) [$ f( D% P - /// 离线消息5 U, u. Y+ A% J* {
- /// </summary>
7 T1 x6 s$ g# z: H! r" w+ m - public class MessageInfo
; z5 W2 y t! g e4 U1 ~5 { - {
* P: m+ |' q' u6 O- }* W) \. \ - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
$ o5 b a# c7 G% J/ \ - {2 a% f! I# i- u- a
- MsgTime = _MsgTime;
: J$ |; B" l: K6 [$ G$ W4 k9 C - MsgContent = _MsgContent;& F. y7 D, ^4 F
- }$ U {% Z) C( n/ {, Z
- public DateTime MsgTime { get; set; }
5 U( Z3 [5 G5 J6 b - public ArraySegment<byte> MsgContent { get; set; }; u- Z0 m3 A' M8 t
- }
, \0 k& T/ b& U) v! s - ; r, u& w9 {0 v U
5 U/ E$ s3 ~ l* Z1 U% R
0 I- u* C( O& K
0 d! J2 h4 v, P0 F( I2 {- /// <summary>9 Q. d; q+ ^5 l
- /// Handler1 的摘要说明
4 h3 h! y5 v& {3 T$ |5 M0 x- Q! ~ - /// </summary>! }6 i3 s( }( O, h0 g0 y& o( x
- public class Handler1 : IHttpHandler, G0 ~" F; ~) l5 g0 |
- {) P7 ~9 D) k1 q3 r: P: w
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
5 Z9 e1 e4 A: G1 \- R - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
- Q: u& R4 L; ~- O5 @5 Y - public void ProcessRequest(HttpContext context)7 S2 L5 ]5 x4 J! c
- { h5 {: S1 B. Z T K
- //context.Response.ContentType = "text/plain";, Y% ~" q: Q: S" C5 U% e
- //context.Response.Write("Hello World");3 g' J! X: h* k$ c7 k
- if (context.IsWebSocketRequest)' q& l* E- O/ o4 I8 M) ~4 [1 g1 Q
- {
( D; c* {3 A% t0 _7 H2 l+ f- | - context.AcceptWebSocketRequest(ProcessChat);
/ c. L+ t5 P$ Y8 ? - } : W# j; n. r9 f
- }
( H C9 o u- Z& [1 v5 ]
4 o9 Q8 d# h/ e- private async Task ProcessChat(AspNetWebSocketContext context)9 t) y& N/ {) U7 u! w& `% f
- {
: c9 C1 E- m) j; ?- X$ E" H- n# E - WebSocket socket = context.WebSocket;* F" d" I3 b0 M [/ v
- string user = context.QueryString["user"].ToString();
* I2 P6 [1 Y1 ]. Z0 ?+ d, u4 c. j - 9 b' p# d1 s0 C* W2 {! \6 {) B
- try0 m& H# |0 Q* u# F
- {0 x- {8 u* o6 P
- #region 用户添加连接池
8 D! R' s) A- x ^- h4 T - //第一次open时,添加到连接池中
* P% @, N# v1 f! @ d( x( @# Y$ L" P - if (!CONNECT_POOL.ContainsKey(user))
7 l( R o- @2 n J2 R - CONNECT_POOL.Add(user, socket);//不存在,添加1 q7 s3 E5 T. R) d
- else
6 F- [3 `" R L* ~3 Q$ L' f - if (socket != CONNECT_POOL[user])//当前对象不一致,更新
2 T* z; t2 g- r$ Z! i1 G) Y: g - CONNECT_POOL[user] = socket;
/ `% C O0 E( Z2 B8 h% a$ G i, z - #endregion9 U/ G$ j1 g) [7 R* C. o) C! V5 v4 y
- Y) F) [: _' {6 _. d! s- #region 离线消息处理
% ]$ m2 D; C% x/ D. Y) z - if (MESSAGE_POOL.ContainsKey(user))0 Y {( W4 A/ \6 _! [5 Q( K
- {
D1 E+ p/ @6 B4 ^ - List<MessageInfo> msgs = MESSAGE_POOL[user];7 Q& e+ U. i8 T5 f
- foreach (MessageInfo item in msgs)- S3 x6 G9 y7 l5 `- U
- {' T P+ I' b# e
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);$ O& g7 Z' l) s8 L/ g) ~
- }/ K7 R( @3 X$ d4 u' W. C) x& d
- MESSAGE_POOL.Remove(user);//移除离线消息
( b1 {! ?. Z5 U/ d& S7 k- b - }- q% e0 Z! O: e1 p: E
- #endregion: [7 ]- \/ L3 r2 J/ ]
- - M* @$ r2 o3 H5 Z
- string descUser = string.Empty;//目的用户% g0 N! N/ C) c8 Y: I, [
- while (true)
3 D+ c4 n2 f& o6 \ - {. ]; a$ h$ Z# y2 B @
- if (socket.State == WebSocketState.Open), F" j; g+ F& {
- {0 n: [7 s3 s1 r7 g: ?' u
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);1 Y; Y7 B/ `+ f5 }# _' t/ g' T+ Q* R$ N
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
# v6 J- O Z& d
2 [" ]( k4 w0 n+ I9 d3 C- #region 消息处理(字符截取、消息转发)+ A" P3 _" N* s7 Y x- `8 K
- try5 S+ n9 c1 e9 J! h
- {6 l5 `+ v5 A, ^
- #region 关闭Socket处理,删除连接池
, F+ s; N* b& \( U - if (socket.State != WebSocketState.Open)//连接关闭8 ?( F0 V( I3 F. O- m% H
- {
\% D1 A6 W2 B9 k) U1 t - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
" D' c# v0 [. |/ _) [! x% C - break;3 x' q H2 U" F$ l( Q
- }) ^6 u/ b3 J9 M. n; O
- #endregion
& s4 b" G) f L3 v( m
+ @/ z; H2 Y- ]3 l1 o: `: i( k- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
2 }% {; Q" j: |+ B2 Y7 V( j - string[] msgList = userMsg.Split('|');
# w- R7 M: o+ c* @0 A% t( v - if (msgList.Length == 2)* Y4 \* U5 z, [6 [4 M: w5 v( A
- {
+ k$ H( v% A$ q) y" H - if (msgList[0].Trim().Length > 0)
" X* n# L6 `0 `0 t p+ h- L - descUser = msgList[0].Trim();//记录消息目的用户; h! r: ]/ j$ m+ _$ C% F: {% X
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
+ o) b3 b( S. n: c0 ^( q - }' J3 T5 P8 }& k) L
- else* Q/ ], B; p; w8 }6 F. d3 N
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));% Z$ n" V/ Z1 S
4 i2 l) |0 ^2 F. S7 \- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线* D; b0 N, J% N2 l4 ?
- {) ]* A) I+ M& p+ H7 C
- WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端& {, ^. w4 |, \. o2 s0 h
- if (destSocket != null && destSocket.State == WebSocketState.Open)
& M: F2 J6 ] D$ T# g+ R$ i, \% B - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);4 X8 p( Y Z$ u
- }/ V' m2 Z# H6 G
- else
5 V5 L9 t5 U5 ` - {
* I3 R+ i5 B. S6 n8 h6 x - Task.Run(() =>
5 E- [: H! I/ ?5 ~; s - {9 F( m0 p; V2 a. S* A1 r8 G
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
! `) R- c" @3 q0 S/ r - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());0 \( _% M' s4 M2 y% z/ L9 w8 B
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息" t v- U/ j r7 z8 U5 G
- });
6 C# N; t1 M* `" J8 f0 d - }1 r" Y6 T+ X. K& K. U; C
- }
( ~+ f$ b4 e& n, D, C- u6 k3 E( H! t - catch (Exception exs)0 q. ~$ Q3 R% q7 v& v+ t
- {3 w/ G2 X* `" u. A! Z
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
. X% ?! |5 m) G2 V% r7 F - }) x! B. N$ w. g' [" | _
- #endregion
+ T n4 }, G1 D( q$ | - }, ?7 X5 w7 w! C j4 B: E
- else% @1 c1 h6 n3 W
- {
: l Y h3 b3 n$ q - break;4 D0 @3 z1 }$ W
- } o$ ~! ~1 ~& P) ]; c: r
- }//while end2 `% e- S/ t# S
- }. l* k# F5 ^9 A- ?
- catch (Exception ex)& w4 L% g4 S* Y8 X
- {1 s+ u; g( x: c6 R* V' P' `. t
- //整体异常处理2 U8 C2 K& x0 Z+ b
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
) ~( H4 y+ ?- O! e; z8 k0 ~ - }
2 s7 y9 n8 T$ Y3 X - }4 u9 h) J0 T' P0 [, G
4 ?' J. c3 |4 ` E: u0 }6 y
; I2 V8 j% i- M4 d5 L7 C- public bool IsReusable
2 j7 x' e- L/ p4 L. k# Y* K - {
- \3 Q3 i" c; ]9 x) I2 ~ - get' g, C; g6 K6 A% V. A* ?
- {
F- T8 R% p- b. r" e - return false;% g' Z/ h) m; r+ J; ~6 a; w l$ C
- }0 Q4 }' x# B8 i& h- R9 A$ y! }
- }1 M- v+ v! w- E6 K1 P1 o& m! I( k
- }# O0 n# C" K/ X4 p- H' i) l+ l
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
f: w$ p& u6 O, Z# z |