服务器端代码编写 1.新建一个ASP.net Web MVC5项目 3 o) d1 @& E: ?* [
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;
B; X, C* Z; r - using System.Collections.Generic;/ `4 U* n& N4 A- H7 e: F& F( S; |
- using System.Linq;
2 e9 Z9 s ?! d0 o1 R9 D3 F - using System.Net.WebSockets;
/ |, S( f+ _ o) f# v. Z - using System.Text;
5 ^' w, ?* R3 Q. G, D - using System.Threading;
; }9 }& J; z4 m I - using System.Threading.Tasks;
2 `3 V. [6 \2 Z5 R ]$ c - using System.Web;
* I* J3 f7 h3 y3 O3 \ - using System.Web.WebSockets;7 j {7 m" d7 H7 V% m% R4 ]: I
0 m/ {4 d8 a, I( L- + `4 `9 c/ ~2 l( z
- namespace WebApplicationWebsocketHandler- m/ x8 M0 A; O
- {
! a7 ^' S2 Z! r9 u: L' C - /// <summary> X. N% A3 @4 W( ~% U6 A+ N
- /// 离线消息
. w5 O8 J7 T% V# B) f - /// </summary>
7 u, l% {% L L: ?9 X - public class MessageInfo B6 h1 F( I8 G, R6 W$ c
- {0 a3 S( F3 e B: b
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)+ r$ X- ^) Q5 v+ |: ?/ I3 | g- S
- {
/ |/ C k) |/ m* }7 d - MsgTime = _MsgTime;
6 U# H# O: W! V. X4 A4 L+ |' s - MsgContent = _MsgContent;: B' c1 M+ b; x3 h2 y
- }
. d: X; l5 l; E5 R# g - public DateTime MsgTime { get; set; }
- d( J* y' K: B, r3 z8 U4 p - public ArraySegment<byte> MsgContent { get; set; }
0 Q9 [8 s v- q4 `! J2 w - }
) s8 h, m1 v# G* q - 4 G* @ c# Q- b6 V& ?
- . n" g6 ~. s# ]) r K
- 9 m/ G8 `5 _$ q
0 ?/ h# i3 |, K" H- /// <summary>; j1 f/ @0 p2 W& v" Q! @# m
- /// Handler1 的摘要说明- @6 r% I8 B# B# P# H
- /// </summary> L w% {* D7 {
- public class Handler1 : IHttpHandler
; j( Q0 ^: a2 g8 K# _7 { - {9 ?6 z1 P3 y0 D6 u# i7 \" `
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池, r& Q2 r' |' X9 o: p" w+ X% N
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
. h; o: m) @# N$ b! B/ B# b$ B - public void ProcessRequest(HttpContext context); k- K; Q4 o6 h' N4 x! X
- {$ ~1 `$ S# }. h* n2 r" \
- //context.Response.ContentType = "text/plain";8 c0 {* G2 g- q
- //context.Response.Write("Hello World");
8 q4 c5 L3 P2 d. o5 l# G - if (context.IsWebSocketRequest)
) V4 ^# {* _ c3 n7 v6 h5 W; U - {3 a1 k) R8 B" X0 `/ S. y& o2 z9 M* x+ z
- context.AcceptWebSocketRequest(ProcessChat);
# A, ~: }8 t7 q3 W - }
$ u2 h- i: G+ x% a& V - }
, w; |8 j" ?" l9 d
& r: a9 L- n2 N, G; Q, s- private async Task ProcessChat(AspNetWebSocketContext context)
' a0 h s2 l. w' H - {8 V6 t. m# B" j+ q7 R! N9 k
- WebSocket socket = context.WebSocket;8 f5 f; V/ P5 g7 S; d
- string user = context.QueryString["user"].ToString();
! l, r2 m4 @ B. J/ B" n
2 h' G. E5 ]& s- try8 u8 Z y: u+ I5 ]5 C6 X1 z5 G7 V, C
- {
" d: j2 y' C4 t2 i/ v0 A A) v; B - #region 用户添加连接池
2 Y4 m; P1 X, \3 I- c. |. C - //第一次open时,添加到连接池中2 l/ d/ c X; ~# Z8 m; G3 J
- if (!CONNECT_POOL.ContainsKey(user))
2 y8 y1 y; E. ` - CONNECT_POOL.Add(user, socket);//不存在,添加/ S7 B/ X! @6 L' m4 b" B, v
- else& s# o# W% z' i# w; b! S" a# j1 M
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新
; E* d8 r0 a( M - CONNECT_POOL[user] = socket;2 ?2 r6 N' W$ K6 L
- #endregion t' c/ l! {$ p
% u7 X3 }- y0 U' j/ F3 Q Q, i- #region 离线消息处理
6 Q+ m$ t0 u+ N5 D B - if (MESSAGE_POOL.ContainsKey(user))
3 e( q t; q+ \, M) S) ? - {7 [% ~) N5 r. ^
- List<MessageInfo> msgs = MESSAGE_POOL[user];
6 I0 R- t! E6 e r( ]$ t - foreach (MessageInfo item in msgs). a0 p8 m9 J3 x* h" y
- {
9 } O& L. h/ T6 z5 F& m - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
4 J; o* R& @& f4 ?! a - }
: A! \9 e2 c! N8 U5 |# A - MESSAGE_POOL.Remove(user);//移除离线消息
- D0 p* m* h* O - }8 M( W$ D1 {7 Q! Q! |9 m
- #endregion+ h' p/ Y: |) L o
6 N) |# x' ]# R2 C- M# B" E- string descUser = string.Empty;//目的用户
8 D+ H X( R Z; r - while (true). S z4 f- O; ~5 i9 E
- {
8 O9 r C0 S4 [/ ]. G! }8 @ - if (socket.State == WebSocketState.Open). K1 K A, C3 {$ m' G! A: m
- {/ f, F' O) d+ l9 r0 N8 F" F0 T; `
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
0 @2 V: R# x* H, s# S - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);2 m0 X ~( p3 q# o* V
8 _/ S. g, X; ]: w- #region 消息处理(字符截取、消息转发)
7 n1 ]4 X* _) C$ A' X5 Z9 } - try
# o3 y1 m% l, w" J3 G! r6 p - {2 B* A" E* s8 A; B' E: j. w
- #region 关闭Socket处理,删除连接池( G/ I$ p+ c5 K, E
- if (socket.State != WebSocketState.Open)//连接关闭
. K# V( R- o* }6 Y# E - {+ v2 b. h6 h' J8 o& r2 p- T/ \
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
2 m7 B* m) X! R4 X. S% X - break;
: H* f6 u* |0 q" N+ p6 S) T8 p - }3 c: Q& N8 Z- G2 \3 G3 f, k
- #endregion/ t: U2 O* A* |
- ; {( ?/ Q& x# |+ S0 b% g
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息$ x9 Y+ N: n* G: v, ^9 H5 T6 g
- string[] msgList = userMsg.Split('|');
% W9 d X) T' F3 V - if (msgList.Length == 2)
: b% y* V9 a; Y* L3 E: j - {
/ j4 t* G% L& e1 O9 y/ h+ w9 ] - if (msgList[0].Trim().Length > 0)( Z) X( F4 W- u
- descUser = msgList[0].Trim();//记录消息目的用户1 h( l+ d# G, y. {
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));- e% _2 F7 H0 M) P: P& f
- }) s& c* X; x! F6 e9 N) F
- else* n' W, O- G1 T% M4 Y) U) l
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
3 G% w* Y* D- u D+ U8 v6 y8 C. W - 0 g1 k+ \7 P. u4 c2 ]4 I; Q3 Y$ `
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
7 W8 L) b: x; }3 y - {
) b. O1 J# \$ E! I& ^5 C/ i o - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
" y# J- H8 k7 W5 [1 s - if (destSocket != null && destSocket.State == WebSocketState.Open)
5 K. q9 p; |1 A$ m8 u/ D! ~ - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);1 B2 y& l% D6 }9 _7 y( d
- }
" I5 C3 Q+ M0 b. o - else4 n6 l' E, M0 l% l3 ~
- {
6 g% f( g* N$ q6 O0 h - Task.Run(() =>+ Y) H6 e; S4 E/ [
- {8 h$ c6 I% o+ A0 ~
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
9 C' A; T9 X9 i+ J - MESSAGE_POOL.Add(descUser, new List<MessageInfo>()); v- p) [, f9 S% }5 t
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息& O! N* C! L7 y
- });4 T) A, k, m( H" W1 q9 X1 \
- }
! T z9 A; x9 e. a - }
6 ~- I: ~, d* ^/ T) {. a - catch (Exception exs)7 F' L3 p2 _% B* U
- {! A3 s3 t. J; z+ g' D* }/ u
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
0 t2 o- I/ T) V6 f( n6 |( t* j T - }, C, y C$ i. P$ {* Q- P
- #endregion0 {5 A7 t4 @: v
- }
2 K; o- _4 P8 x - else. V* V8 ~/ k0 x* p: ~
- {
( s1 q! Z5 p: M) q F8 k) K! t - break; L) I6 A9 `) ?3 \3 g |
- }3 ^9 u0 S8 K: o" b4 }# M4 c
- }//while end
: R& W3 J' g; i- x! V - }- G1 d, X! \. _7 v
- catch (Exception ex)
& H# R+ |% c' e$ h8 G* ?2 V$ w- i. h, v - {
- b0 N- c' [. P8 S+ [$ K8 ^ - //整体异常处理
# {7 Z: f7 x6 A, r$ u& g7 W - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
6 h1 z: G& ]& M q6 |% o - }
9 v* m; ^" b( B# F8 H u# i h) y - }
5 ^/ Z' u# @( ?# P3 a
* i* k( u# Y; J) } j* N! l/ U
: }& ^7 i/ u, B. {- public bool IsReusable
8 A% y* Y3 l* x# A6 ` - {" e% Y4 v/ R+ S6 k
- get7 y/ y' Y" M0 n+ I% f% P
- {
/ e$ g5 R/ o' E* n - return false;. i7 A+ @; v4 L
- } U1 {% v4 Y J% f0 {; W( h
- }7 m8 @. ]" J( o# ?" E
- }
3 Z" d" O7 T; U% n# h1 L - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
( H4 i5 `4 l( C }8 [' [" A3 A |