服务器端代码编写 1.新建一个ASP.net Web MVC5项目 . o$ N' j5 l7 w! N+ {
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;" w6 Q+ Q4 v7 C! f% v
- using System.Collections.Generic;9 x. q& d- e# p0 v$ Z0 P; E
- using System.Linq;2 s3 {) _; o6 n* h) [; p. c' s
- using System.Net.WebSockets;
$ d/ Q/ _) P# b2 { - using System.Text;
% w N8 ~4 C$ T5 H$ ^6 p - using System.Threading;
" e2 p' t; G) S9 B0 z' f! ?2 w - using System.Threading.Tasks;
& X) o: M G! w+ ]# }+ Y- m0 ] - using System.Web;& F5 {3 B( o9 r/ r8 v
- using System.Web.WebSockets;
: e7 E) {* P& E( I9 T - 7 B6 Q/ v, S- s: E; h4 B4 y
- % z$ T" _ b: x3 P) t( i: P9 n
- namespace WebApplicationWebsocketHandler3 f5 C2 p; ?! p# [! }
- {' _( ]1 ]9 Y7 Q& \- B
- /// <summary>8 p4 W; I3 F8 [2 v1 ]% A! E
- /// 离线消息# ]2 W. j- L1 Z6 _9 I, Y$ Z
- /// </summary>
: H& z9 p/ Q! ^- V* s0 @ - public class MessageInfo0 r+ h+ s& ]+ ^* T" N/ C
- { C. h5 t' t6 e$ X6 B! t+ W5 w
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
+ Z, |2 b7 K8 L" N" B& ` - {
" B/ o0 C. v) @- [ - MsgTime = _MsgTime;* D; H; i$ y% u( T4 I' b D- k& C
- MsgContent = _MsgContent;- H! M/ H) j- y% q3 T
- }% w1 @/ Y: W; `% S+ p) u0 g# T2 @
- public DateTime MsgTime { get; set; }4 z, R0 L9 `4 R1 C& g; Q; G
- public ArraySegment<byte> MsgContent { get; set; }
9 ?. [" b* I4 _. h/ n - }
' x/ q1 m! e; P$ z3 e% z0 S - $ ^5 ]$ N/ r8 a9 l5 G
0 \) y6 {! B2 n
9 {, O# _5 G2 P8 W" h5 Q- # A p, @5 D6 _+ N
- /// <summary>
( B4 }8 W: H. v/ [7 i V - /// Handler1 的摘要说明
. T1 }: g# c. W' [) z - /// </summary>, Q6 @# s1 g5 [2 c2 G& h% Z: X# D, P
- public class Handler1 : IHttpHandler
# e7 V0 \; i3 L. P/ y - {( C. z2 Q( Q; c" ]/ r/ h
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池- U6 }% _% Y l$ \0 p$ h
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
$ R, a% w) G+ N, W3 T - public void ProcessRequest(HttpContext context)
; |9 o, i( Z" o' h" M9 I1 p0 e, f - {
% u: l# X- ?7 k+ ` x - //context.Response.ContentType = "text/plain";
9 W! D8 ]+ I) p( w9 M# I& W: v - //context.Response.Write("Hello World");6 l6 S! y8 D5 }+ [
- if (context.IsWebSocketRequest)
5 N: Q4 p1 c$ u7 _! D# \ - {2 ^0 { j- g! |# i8 p% ?
- context.AcceptWebSocketRequest(ProcessChat);. X+ N% m- S8 w% ^- X& O, h: J7 u
- }
% ^$ b( m- k* A: H. S# Z - }: F( J4 L4 [4 {! Z, g' D
7 s) U; {# c1 X8 R, k- private async Task ProcessChat(AspNetWebSocketContext context)
6 {+ `# ]- }! u! w9 i8 a - {/ b* u: Q6 ?/ Q. N! K$ i( v' J+ S) n
- WebSocket socket = context.WebSocket;
6 V: D9 l+ d/ q) c0 e- @- ?1 {; V - string user = context.QueryString["user"].ToString();: [" f$ n+ U5 u7 ~9 L( D1 L4 k
- - h# u; R1 \& t$ e' k/ O( d5 ^; r- g
- try
5 V/ P' u4 ?2 t( x6 Z4 P - {
7 m" h' O% y4 c! q, n/ l - #region 用户添加连接池
. ^/ X9 S/ l( `0 ] - //第一次open时,添加到连接池中( F( {$ g. N- Y" ?# s4 F+ H
- if (!CONNECT_POOL.ContainsKey(user))
. O- A+ r8 X" U. g: r1 v* D - CONNECT_POOL.Add(user, socket);//不存在,添加: Z% `" `( `8 A9 m
- else; V8 m- b5 A1 ?( ?
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新8 ~2 Z: ~# m9 b$ }4 L* K2 C
- CONNECT_POOL[user] = socket;- f& e# b) M" O9 l# T2 P
- #endregion4 F2 s: e) B5 Q8 {4 P
- & _( u8 V! }# Q! [3 G
- #region 离线消息处理
2 \1 n4 o3 H8 \6 Y' n1 r7 h7 r - if (MESSAGE_POOL.ContainsKey(user))
% S7 @( w' L! r* z' c8 i - {# Q1 A k, z* ?6 O) [% ?
- List<MessageInfo> msgs = MESSAGE_POOL[user];7 F0 r9 d8 h* ~; Q
- foreach (MessageInfo item in msgs)2 W6 ~9 P. M' Q( H
- {
0 Q2 z% k- B3 C& @$ o7 `! ]5 q - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
" ?) u5 d/ e/ [9 f+ o) |( j$ x4 G - }
. a0 }7 z* L6 X6 S$ P - MESSAGE_POOL.Remove(user);//移除离线消息2 X c* G ?2 b( u: \/ B8 T/ }
- } C. W$ B% @4 V+ ^1 @4 ~/ i! D
- #endregion
3 K- _- `0 u7 ?3 z. G* ?2 B - 2 n0 l* _* u# d/ H6 B5 p @
- string descUser = string.Empty;//目的用户% f6 ], `0 a* j& t. J0 }* h
- while (true); ^+ g* ?- m& h1 y6 C
- {
! c4 x% r- z, E- H' U0 o( N9 ] - if (socket.State == WebSocketState.Open)
+ I& p& k, d& I4 t7 @- g) \9 Q/ s - {; m. f5 \, I" B8 D9 d$ t+ b v+ C; U
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);
3 J3 Y& m( ^4 { P - WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
: N2 E4 ~; {1 `
$ t6 r. B+ I; ]) R2 o8 w& D. Z% e- #region 消息处理(字符截取、消息转发)
8 W3 X+ w0 m$ T" O - try
- j9 ]! p u* D* f& L - {
: H; X$ i/ A& E9 ] - #region 关闭Socket处理,删除连接池3 r. C8 f. P' A& Q, T- z) M- k. T
- if (socket.State != WebSocketState.Open)//连接关闭% P2 A) ?' }, W5 x! l
- {
S- [$ Z1 ~4 t- x - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
. b' }! `# g- O. O8 u8 s - break;
0 T2 n+ v8 i& _. x/ f0 o5 x9 i - }- X& J5 f. J- y r
- #endregion
* j0 z6 G* `$ I
! t5 n+ k& n5 y' }& F- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息$ ~* h, x) ?1 \$ B- ~
- string[] msgList = userMsg.Split('|');1 [" q% h& n' \5 v
- if (msgList.Length == 2)4 r; V; z+ A+ [
- {
9 E! J3 T+ h- u - if (msgList[0].Trim().Length > 0)
$ L; } V+ ` d Z - descUser = msgList[0].Trim();//记录消息目的用户
3 a: h- I3 N8 Q0 c2 T+ z$ m2 g' k `. U - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));7 k! o7 ?" N( E7 F
- }
( p+ G z) f* D- ?' W# c! b - else
^9 E& I" e) l1 ` - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
0 s I2 A' F/ F8 x7 I Z+ q& Y
+ K* j, g# B3 v- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
5 l/ [) ]) W9 s6 R" D9 Q, a% r" X - {
/ `+ H' u D# v9 r$ g - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
( d% G8 e! r5 q2 Q, k - if (destSocket != null && destSocket.State == WebSocketState.Open)
7 a, |$ {5 w$ I, X - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);. d% N8 Y/ v, i6 A( Q% h- X7 s
- }/ L9 ^: {3 t4 Y5 U# Z0 n
- else
, _; |& ?6 R' h N8 P+ m+ k7 d - {8 A( w n, G( b; m0 v0 i& P; u
- Task.Run(() =>3 s \$ k7 J% ^
- {
% \9 G: a+ L5 Y - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
# z/ f& b. f- p. M4 M1 S M1 I - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());& e8 ], @0 Z" `) ?3 }* ~, \
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息/ g- i }7 D6 P
- }); X3 Y) J- w% ^. x8 ]' `
- }5 W+ z. p8 g; h- \
- }
3 j; X" a9 U9 h, n - catch (Exception exs)) R1 v: x% e1 T* J. Z5 m! u1 R
- {- e. z* a# B. D! C2 @8 ^/ N
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
# Y8 k7 v. G/ y: m, V - }5 q: @+ ?+ D4 x1 x! L' g r
- #endregion
1 ?& C' f! N) n0 L - }
5 ~! k8 W7 X W - else) V$ Z8 F% w6 y/ K3 }3 V
- {
8 M& m6 R( q1 m+ A( O+ y - break;8 d" |& l8 M) U
- }
& M% C" J5 v- u4 M) @; d. L! E0 w: d - }//while end; R3 a! D& w" U! w% M* Z% V* ]
- }/ T( r' T* t' a) m# O
- catch (Exception ex)
`" {2 A z2 a. b! | - {: t6 r9 ]1 x, C, j% o1 T- J2 h X) e
- //整体异常处理1 k$ o2 W" l$ P+ R! o) f% ^' @
- if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
0 q6 N& ~( H$ R }/ c - }
9 g4 z% u/ u2 u/ M# M8 l3 Z$ ] - }
1 C" M7 \) `/ [! m: L" V- u/ Q) H
2 t1 s% i4 X& a& ^, V1 D$ k
! R/ V/ u g. [/ A7 s* I) N0 i$ @* I7 W- public bool IsReusable! X# s. ?: l, Q$ X5 y2 f; C
- {
5 i) T+ [: O. f% O - get. y' W3 N$ _8 {1 Y( w& q' R9 X
- {3 ?' m4 @ }% _8 o! L2 M1 C
- return false;
9 T% g3 x; ?. F2 p- {) W" j - }" `" I) E5 r d; L% c8 n3 @6 u: f
- }
& x" r9 }/ l: ^, ]9 E' ^2 ?4 v - }( U7 B& G g) M8 c3 d+ Z4 ~
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 % E5 M2 z* _' g/ Z7 B* y! O
|