服务器端代码编写 1.新建一个ASP.net Web MVC5项目 0 o" Y4 I. W" i0 ? I# }3 W- K' s. e4 e, t
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
9 e8 a: t& q" Y - using System.Collections.Generic;
2 O* Q9 [1 i9 a6 h3 U% T - using System.Linq;7 z3 f" v4 j! W$ `, J
- using System.Net.WebSockets;
) H% s. y) W/ i$ h! j9 S9 ] g - using System.Text;
4 _4 h/ d$ i4 }* f& g4 W4 [5 L - using System.Threading;9 Z4 Y7 p5 m0 f8 i
- using System.Threading.Tasks;
3 v, F6 P9 j( X, b3 J% N - using System.Web;9 m! B1 n7 q5 Y+ A2 M. T, Q9 N
- using System.Web.WebSockets;% B3 P5 v5 A; \- h* p
- 6 A! c2 i; b' ~" S
/ E' i. \8 p9 t+ L- namespace WebApplicationWebsocketHandler5 _% _* S3 }2 m# u
- {1 \; W0 l) p7 ?% ]8 M) J
- /// <summary># Y- [$ K2 m8 z3 L v/ r2 X
- /// 离线消息" k" O) o, k' @0 N' P- f5 C6 c4 z
- /// </summary>8 C6 D' B$ a Q& U
- public class MessageInfo
! b$ ^- o8 b$ E U, w5 \ - {# B0 h, R) J5 I0 K! j( n5 F, N
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
1 H x6 S- W# G, H* x0 Y, F- | - {) T% S$ y% G9 r' U5 n2 o; Y) H
- MsgTime = _MsgTime;6 n' D# |& k H V9 J4 f# B* L
- MsgContent = _MsgContent;+ k$ y; X) k0 `
- }+ e% q8 k0 I- f! J5 m
- public DateTime MsgTime { get; set; }* [ V/ G$ I& r, J
- public ArraySegment<byte> MsgContent { get; set; }( j9 p: b X$ i! {3 n
- }
% h$ u; r$ F2 X) Z @1 N - ! d1 B& \, q/ Q- F; G
- $ B" e& m; |9 L/ A2 m
/ Y8 w: v0 `2 d* S9 J0 t
( C. i$ ?, c* @5 d- U+ _2 n+ j1 Q- /// <summary>& z: V; C( V% p) k9 X) ?
- /// Handler1 的摘要说明/ T0 C" P. X9 a
- /// </summary>
$ ~% R. e( C4 Y( y( l" V! D- _ - public class Handler1 : IHttpHandler
! P2 \' G9 u0 r! R$ E" s/ J - {$ v& y8 u4 Y$ v' ~8 |& t- U
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
`8 j# n1 m* k- A. U1 a Z - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
, w0 I4 t( o4 g - public void ProcessRequest(HttpContext context), s, Z( Q7 b6 y+ u5 u3 K; i2 p
- {
# l) f% J6 U0 N9 \ - //context.Response.ContentType = "text/plain";; A2 o1 E t6 o& L+ q
- //context.Response.Write("Hello World");4 d0 ?& {4 Y5 o' e
- if (context.IsWebSocketRequest)
- w# ~; h& z5 j9 u9 ]2 T - {
# k. `% o4 [$ a8 O' P5 ?8 E5 y! z - context.AcceptWebSocketRequest(ProcessChat);; B4 o3 Z; G6 J4 W' U5 ^
- } 8 I# Z1 t' J. `$ G% L' U0 w: {
- }% |4 Q% o7 F! [# h! u
- 9 C Q' a4 l% n0 @
- private async Task ProcessChat(AspNetWebSocketContext context)
3 u; _$ v% P1 S& ]% W N6 r - {3 x9 E3 f0 P* j8 o1 w% I
- WebSocket socket = context.WebSocket;# ^9 M i9 [ V5 _3 K- z/ P1 |2 ?
- string user = context.QueryString["user"].ToString();! C0 ]' X. z! T1 [ j- [ l0 R( {
- - W! n5 r) ~+ t! e4 z+ Q
- try& U4 v3 N4 U) G! H3 s& Y; R1 X5 a$ Z
- {
# a, G: B! R7 f. k - #region 用户添加连接池& y C5 k2 p3 e9 C. K; n3 y, Q
- //第一次open时,添加到连接池中
2 H- S5 \( [9 {9 v - if (!CONNECT_POOL.ContainsKey(user))
: W# D7 s! h) _9 E - CONNECT_POOL.Add(user, socket);//不存在,添加
7 `8 k9 @; Y4 I, y - else' Q3 Z5 [" A+ r$ ^# u
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
4 _) k5 h9 [+ N" e/ r% e8 L - CONNECT_POOL[user] = socket;
+ O( G: E6 l3 t2 p* N - #endregion
; ~% s! D9 m. P% m* Q" j g; r
& d' N+ v4 v$ G' }4 m- #region 离线消息处理
& e- W; c0 N6 K# m* ^ - if (MESSAGE_POOL.ContainsKey(user))
# h. E$ H& ^6 }# Z1 d1 j - {/ @ a4 c) B( s& \' ?: [3 r1 d
- List<MessageInfo> msgs = MESSAGE_POOL[user];
# U! V% N" N" e/ I2 k - foreach (MessageInfo item in msgs)
2 ^ t p `$ l2 h - {, @8 g# ~3 K% t; P6 }, m! \- j( z; |
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
9 y) i1 r5 Y! O4 s0 U - }4 T+ @7 U4 h0 i8 w
- MESSAGE_POOL.Remove(user);//移除离线消息8 i3 A8 T- Y5 L$ ]2 |
- }( I( i( n2 ], l/ a F* B& j
- #endregion
: Q, U, _3 d! M4 ?! y1 k - $ E/ |* H+ h4 t6 y, J% Y
- string descUser = string.Empty;//目的用户' R6 k6 A7 }& C B
- while (true)
& i6 q4 Z3 s$ ^% n - {! I$ X/ J1 x" h9 G, l: T5 C
- if (socket.State == WebSocketState.Open)
0 j* I; |: i$ J3 R/ a - {2 t! L4 ]( H5 Y/ c" _7 O: r- n
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);5 R4 G$ K3 s" ^% ?* N4 i1 a7 e# ]' Z
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);1 a1 ]- e0 b2 a4 y. L2 H
, J( }' V. }, p+ J4 v0 d7 `7 e2 j4 N- #region 消息处理(字符截取、消息转发)4 ?& V, b: M& r1 y J {# U
- try& Q% H3 m9 Y0 b/ a4 M
- {7 x1 B: R* f9 v/ I0 d& B
- #region 关闭Socket处理,删除连接池$ m. i0 R3 Y7 ^ C( f- F
- if (socket.State != WebSocketState.Open)//连接关闭
$ r6 r. H( K1 G; u - {
& R- V" V6 e. V2 K - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池' A' T% n* Z/ Y) x9 F
- break;
" @3 Y7 e. E6 S K- } g2 H# P, C - }
$ Y Z4 u8 P- k* m( P) d - #endregion4 K' e, [. m# S/ O& w
/ ^& l3 f! B& k" o7 |- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息7 \& x% }6 g$ W
- string[] msgList = userMsg.Split('|');
5 W( x7 Y8 d2 j! x8 }4 f - if (msgList.Length == 2)% C3 \3 y5 s1 I
- {* E/ G2 E- I3 [
- if (msgList[0].Trim().Length > 0)6 \ H8 Z( |6 K0 r
- descUser = msgList[0].Trim();//记录消息目的用户
! D$ {* g) y# ~. \ - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));% x1 }# f' b, f+ s
- }; S% b7 p7 ^ @, q# B" t
- else1 Z/ Q2 Z3 E" K3 {
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));4 X- s+ r6 x1 B! {
- # N: A, C/ ^2 o
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线0 F* l, c' U/ C! ~2 v; r
- {
" F) h. f( ^# M3 o* J r$ h - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
7 }9 R. K. O; G' J - if (destSocket != null && destSocket.State == WebSocketState.Open)6 C8 O" ]5 }& R8 L
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
/ h3 b7 U+ X# @4 X - }* q& C0 H5 I( ~0 Y F' x+ ?
- else- U, r' ?: `5 J7 w% G r
- {
" H" i; e/ ~3 f- x - Task.Run(() =>! p9 Y/ W4 w7 v* D3 O
- {6 ]; P/ C0 \- ?, U
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中. f }! J" q7 A) W% p" f# F8 M
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());) Q9 d+ l' Z n- r ^. x
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
" P) C; i$ N1 k8 k& Q - });
$ d, H2 Y3 ?' R" @' G% } - }
( W: q0 ]; y7 K' {4 x3 z# x& | - }
; d" N/ P$ q* Y3 X: ^ - catch (Exception exs)' \$ ]. e* u E Z7 I- `
- {
. o$ a1 \7 R% y% ]- a - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
% K2 \9 K. G$ i @ - }* t- Y$ d# f1 _3 A
- #endregion
( C# f8 s9 S# ]: m1 @$ C& h - }
; `& c+ i$ T V& c3 ?( N9 O4 B - else
! N: V5 ?% N+ r" g4 k2 h- J - {
& u" D! T2 u. Y h& A - break;: Z5 w+ P& k! E5 K
- }1 o3 t4 E& \, e( ?, B
- }//while end2 E# c8 y% B2 S
- }, K7 G1 X8 Z/ U9 t. t! q
- catch (Exception ex)
" s6 E, ~6 A* z o R9 w - {
* l! {& k/ q. L. f$ K$ Y - //整体异常处理7 y$ I) |/ p- y8 o0 X3 D8 D( x* y+ K
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
- ^6 r5 M/ O( H0 W6 b0 |# S4 H - }1 R1 ~5 b# `# r; s, I6 K
- }
' L, A! t3 H3 {9 P# `0 w( Y$ m
) g; ^& O. z. R( `
3 `1 x4 p6 M0 t- public bool IsReusable
; |( u6 Q( z2 }% g: b - {+ a0 N: ^3 g$ P2 l: Z+ _' i
- get. s; C' d3 v, o5 r( p
- {' e' C, U j: c5 s7 n! u- V! D
- return false;
5 Y" ]5 q# t& f/ D$ X - }# I! I! V, S* P( m1 z& c* [
- }
W5 J5 r- y2 Y w3 j - }, B1 G9 T |$ Y4 |
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 9 m( Y2 @2 m% Q
|