服务器端代码编写 1.新建一个ASP.net Web MVC5项目
9 R4 s; x% ?- R) X# P0 j' X2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
& q3 Y" }) V+ o7 Q" U; K% N - using System.Collections.Generic;
9 U, A( M F7 J0 W- z - using System.Linq;% ?) ^. {3 E% J4 L. U
- using System.Net.WebSockets;5 v8 q' {9 Y8 [$ z
- using System.Text;1 T1 M; |4 Y* T3 y+ x. J0 g9 c
- using System.Threading;7 t3 T6 C$ N% z& u
- using System.Threading.Tasks;
0 Z! q+ f3 u! O3 d7 d! ] - using System.Web;/ J( l* x3 ?$ j2 C* p
- using System.Web.WebSockets;
! R+ P4 F9 s& |+ C6 k2 o
. G" s9 T9 ^2 A/ \- 8 b6 S; T, w: [) A% s1 U- M
- namespace WebApplicationWebsocketHandler
- f$ K1 V6 q# T9 E) R' e7 i! e - {
8 K0 }4 i) O' V; n; b - /// <summary>
% _. u4 v) i% l/ O- [ - /// 离线消息/ S! S8 ^8 o, S+ [% B: }
- /// </summary>0 o# D2 X% y, ~
- public class MessageInfo
- v5 j1 Z& ?1 F - {5 B5 |: H' ], x; K
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
1 p1 u% @: n3 {3 S2 }& Z' @ - {$ O( C3 B2 H$ U, R3 r
- MsgTime = _MsgTime;
! ]9 D4 T8 R+ t, \ - MsgContent = _MsgContent;
* h: }7 l/ S6 ]0 L - }. I7 z8 n5 g6 O. w T, N
- public DateTime MsgTime { get; set; }
" x0 G, S" s# _4 s( c. M - public ArraySegment<byte> MsgContent { get; set; }
' X2 f8 L. Q) _4 C& _$ _ - }; \5 s' f8 X6 [
- $ m$ G" T9 C0 O! J$ r2 |
- ; U5 @6 ~6 |4 w' l& C+ \: Z
- * ^3 o+ r' A1 U- s% l: A& C7 k' r
- 4 o! p: d3 i6 N/ `
- /// <summary>; L% g: C" X8 j0 V& P
- /// Handler1 的摘要说明
- n" `, L" d' T$ i" r* ^8 { - /// </summary>
' O# Z; `/ o0 b Z- ^ - public class Handler1 : IHttpHandler
9 Y+ P& ?8 A% m, h$ b: V1 T - {
; S' S: f7 j) D4 H' `% q - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
, ]2 }4 [1 w- [. S" D - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
7 U5 M1 u1 C7 u* c! t7 i: q2 U. G - public void ProcessRequest(HttpContext context)2 B$ ~1 \. O% N
- {% ?, L r3 V' I6 N; n* m: r( `
- //context.Response.ContentType = "text/plain";
$ Y1 B1 O; o: Y$ z - //context.Response.Write("Hello World");
: m/ O0 Y3 @7 ~4 ]4 r3 y+ t$ Y% J0 R - if (context.IsWebSocketRequest)$ o, H* O# I' e9 h" ?
- {9 o @. H' z. q" l
- context.AcceptWebSocketRequest(ProcessChat);, l" ?0 B7 x/ |$ w; M: o: n
- }
6 Q) U& \2 s% I7 P; B - }
- }+ X" l4 N. K0 N2 [5 j
0 j5 f( c0 |7 T! R2 L j3 V- private async Task ProcessChat(AspNetWebSocketContext context)
$ a0 Z- T$ w5 u+ h; e - {2 O7 D4 ~; o$ z- ^0 V) ~
- WebSocket socket = context.WebSocket;
8 K/ |/ m* \7 \, g% s5 e5 m2 r' x - string user = context.QueryString["user"].ToString();' K" X+ r, m+ [9 u8 |+ L% @1 Z
* ?$ m1 R' T0 f8 Q0 S3 y1 O9 i- try; F1 A I, X; i' D
- {' w. z1 ~9 L; r$ |
- #region 用户添加连接池; {6 x* W: G0 V0 z. F3 X Q
- //第一次open时,添加到连接池中
) i: \- ~- W9 w - if (!CONNECT_POOL.ContainsKey(user))% G: w! n8 c5 S1 m2 M: [* u+ h
- CONNECT_POOL.Add(user, socket);//不存在,添加7 ~% T8 _( u) [# T
- else
, V. F8 a- Z7 ?$ N# }$ k" l - if (socket != CONNECT_POOL[user])//当前对象不一致,更新1 c+ q6 {& a: a2 t, H! _( f7 O
- CONNECT_POOL[user] = socket; K/ {8 P! [# v( [; L
- #endregion0 V7 e' X& _& R8 L% x
- 9 r [: K% ]6 {$ B
- #region 离线消息处理' Z9 [7 a" f- r' E* k4 H
- if (MESSAGE_POOL.ContainsKey(user))" x# P/ S+ J6 ^% a+ E% x9 `/ O
- {1 |% Y" a' ?2 a1 G) s! o
- List<MessageInfo> msgs = MESSAGE_POOL[user];
7 i! E6 U+ m; J6 g; S9 z ] - foreach (MessageInfo item in msgs)4 `. P- _% e2 }% Z) R
- {
6 _: M% U: u+ p - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
+ ]( W2 |; f6 K* f - }! N* B4 n8 N2 n, e7 f3 P$ s
- MESSAGE_POOL.Remove(user);//移除离线消息% X! k) G" a1 O7 {
- }. u. v1 L/ n) W4 w7 C$ C. g
- #endregion
; s& C* ?( u9 f. O
y# Q6 c. u7 p: }" T" U- string descUser = string.Empty;//目的用户 p! o+ ~! {6 `, S. m8 P; U
- while (true)
: T& M8 F& W) n$ m, a7 N - {. c, N2 A) ^+ v1 U
- if (socket.State == WebSocketState.Open)
5 T" Y& `4 N( [% F0 F# K% N2 {0 ~$ [ - {& p* \% z/ w8 K- j0 M7 ^
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);# Q; C5 R8 [/ J: d
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
. R5 G/ x _$ O6 P! k q - % Q# ~5 S1 [2 d7 n) u8 B. i+ E
- #region 消息处理(字符截取、消息转发)
% G9 O: d8 Z5 r4 s6 T - try$ ` M5 I8 L( g. R O9 h Z
- {$ B- [* [8 A1 L: ]# ~4 Y& `5 A
- #region 关闭Socket处理,删除连接池
$ k3 c: z+ x, v( E, H) J - if (socket.State != WebSocketState.Open)//连接关闭 K: ~# p; D& D" R' |
- {8 Q, H! l# K: i F
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
K+ o, }. V- h' y3 Q - break;
* D, f% |$ s! y - }
* ?5 G: E5 M1 n; |9 N& H, M( w - #endregion
& j' N6 }, G6 R+ B" D - & L5 s1 f( X, r/ `$ @7 S
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息3 O9 e- m+ S+ j5 }
- string[] msgList = userMsg.Split('|');% s" \5 C$ L" O1 Y* ^1 K8 X
- if (msgList.Length == 2)- l7 ]$ O: g5 y! u9 T. B; ~. D
- {2 {8 @; a# m, t( m4 o$ M4 b
- if (msgList[0].Trim().Length > 0); Z; S8 m6 ~6 W5 u
- descUser = msgList[0].Trim();//记录消息目的用户$ d, k; k6 I) X6 _$ M( T6 F
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
# R; k; V- \4 T& G7 c - }9 f0 E& X5 D5 Q5 x- m
- else' k' V. L7 v$ O0 s3 i# o
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
0 W" n+ I% u9 O3 q0 p }, `/ Z
3 Q5 E$ \7 j7 ^ I& U8 ^+ r K0 E- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线( k4 W) v5 ~# M, m3 N: b
- {
( z/ }; m) G- P6 f - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
" Y2 }- D7 ]) I1 T# D - if (destSocket != null && destSocket.State == WebSocketState.Open)
; \3 ?0 }/ `! R; H2 b( {! ^! `& k - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);0 a8 f9 [0 i; S: l, f: G
- }) l2 B# p o9 v* @
- else9 X0 k$ s, W1 @' y* g! q4 X- s/ y$ I
- {
. D3 E8 o2 V; F5 e( w - Task.Run(() =>
0 g" k5 L7 W6 O8 q; Z$ ? - {
2 U# Z* k/ p& s; z. W5 Z - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中# |5 |, \6 u7 h3 I- ~9 v7 @6 ?
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
6 n" J5 o$ y+ v" S* K3 I, T2 e# d - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息, e& x! z% w# c) h( M! x
- });
$ a4 d; w W- P8 [: Z1 F - }
0 k8 x9 X" l! |; @0 {# X - }
8 m: {* {1 J2 q5 N" B - catch (Exception exs)+ W' H- |6 u5 [+ ~% V3 s
- {: a& D( d2 f9 f% ^/ ]
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息0 n5 V( V3 T/ s% Y* J
- }
: o) x3 V I7 C - #endregion. |& y ~0 d* v
- }
6 u9 z8 L" L% a9 X. l! D+ Y8 Y - else
2 y; f x5 w3 H$ U S - {; K! _: Q# R8 c; k r; Z% w
- break;: N/ ]$ I6 N0 ?3 W4 h
- }
/ v% C5 n: y! q9 l. p' q, ^ - }//while end8 ~' d9 A# R. x( |
- }3 p, C2 _, c5 H5 u/ v* d
- catch (Exception ex)/ E u& ^8 h5 h* s4 E
- {
- g# `8 R4 \+ ` - //整体异常处理2 j8 E' u8 ^# A0 p& G
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
" z' R& h3 q2 A. x) H$ J+ |6 Z- a2 ` - }+ R/ c2 L# L5 k! @
- }: W& |1 [0 _" E( s# d( S
- ; T$ N& }3 L$ J; d: m; f
- : m9 A1 n, _* `, i1 Q) {- i
- public bool IsReusable
, i! R/ \* V5 |0 f - {
! N" z, Q) k1 Z1 H; E - get
. P: Z1 a+ C. @1 n+ L& G - {
! J- o. V1 n9 W f - return false;
( @. t+ R* V2 x! ? - }
4 q) A; |. n7 G1 Q5 I# g- X* g - }
7 T" g' l' ^/ K' z8 R - }8 s2 H* l3 ?# p* W6 J
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
6 A# R7 M; ^. n8 z1 u1 D* M |