服务器端代码编写 1.新建一个ASP.net Web MVC5项目 8 A% k* O& T ^; h0 d' x/ @ s( i
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;% w# @) g' |: Z) P
- using System.Collections.Generic;+ o. t2 M! t/ k8 }4 i. a% d
- using System.Linq;
h0 F1 K y, Z/ ?& D* c - using System.Net.WebSockets;
" \2 s4 H$ ~0 g2 A. d8 R. k$ x/ _) v - using System.Text;. j% F7 I: Q8 l# o6 ` N9 a
- using System.Threading;
1 p4 S& Q8 X1 I. W2 Q- Y - using System.Threading.Tasks;6 L" C& r, k/ a; {
- using System.Web;6 V6 ^* s+ m1 N k: ^ R
- using System.Web.WebSockets;
2 p/ l7 {2 W. l& ~
. g$ w3 J5 V0 r; s8 J \! x- # F6 A6 a; p+ H/ q; u6 ~6 S) o: O" o& q
- namespace WebApplicationWebsocketHandler
8 c8 `% j! G3 ~0 Z- V$ c# B# s - {
7 I# v. h, h* k- F: J* z - /// <summary>
# n/ Z. }& G) q- _9 ~* O$ v - /// 离线消息
4 t1 k/ W9 F1 P - /// </summary>
1 C4 W# L% y- q+ R9 Z& H - public class MessageInfo+ G' ~+ p7 s/ ~) Z
- {
, p( C* D5 j0 x# P8 @9 |0 N" f - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent), a2 U3 d3 s+ N3 e: i8 U
- {) m7 E) ~& S9 t/ d; A: w" |) L
- MsgTime = _MsgTime;; E( j5 p* o( n& e2 }! ?) J* ^
- MsgContent = _MsgContent;
8 N* f0 Y7 k; c - }, j3 @. ~' k3 W( F
- public DateTime MsgTime { get; set; } Q9 A) k" z: R8 h3 m+ g
- public ArraySegment<byte> MsgContent { get; set; }/ E5 m. @6 j# A G9 X
- }
7 ]( s4 r7 k8 Q0 R2 l$ l/ \
) [. y+ M" s% A8 d7 G- 6 p B0 b5 P9 g) P) e6 g4 l
2 l x5 j) i a! u/ g
* l/ @# X; p; k2 @. l1 D- /// <summary>" E% j- V) c- b7 Q' ~
- /// Handler1 的摘要说明0 Z" i* C5 W6 y: X
- /// </summary>
* D$ w0 u/ p& ~- r% l7 I8 z - public class Handler1 : IHttpHandler3 S' Z% H) u+ ?/ i o/ R: `
- {7 c/ G/ p: l o- n2 C
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池
$ a) t" e; ]2 e - private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池2 `# y+ d% I/ A( {3 ^/ f
- public void ProcessRequest(HttpContext context)% C3 ]2 e4 {2 m8 _9 T
- {
% s3 R% h9 z0 _ - //context.Response.ContentType = "text/plain";
6 Z# I, p5 q" f9 U0 {8 q - //context.Response.Write("Hello World");( b7 r( w- A8 `& ^& U1 K& \
- if (context.IsWebSocketRequest)
. ^" [2 t5 R8 Y. b# o. a3 z' u" O - {
3 X) t) Q, l; N6 J - context.AcceptWebSocketRequest(ProcessChat);; p9 ~" ]6 I6 T
- } ( {( V. Q: Y; T; W% g
- }
+ F* R4 I9 o: E" {/ a - ' }. J9 E) K$ G) s- ~. l; r9 J( _% D
- private async Task ProcessChat(AspNetWebSocketContext context)
5 W4 i: _. X6 [) X( G: n - {
% w# L0 W" }8 n1 D - WebSocket socket = context.WebSocket;$ P* f: h9 {6 W9 d
- string user = context.QueryString["user"].ToString();8 e' r6 {- f% E7 ?' K# z6 a9 _
- 6 u5 l" E, ~' {" Y
- try3 Q) R4 ]9 h/ W8 O* ]5 D; ?' q
- {1 ^$ r9 z* |: D7 I) G/ G! j
- #region 用户添加连接池
: U& h8 m3 A1 q5 e% q% ~ - //第一次open时,添加到连接池中 I; ^% H2 Z: l1 s7 ]% b
- if (!CONNECT_POOL.ContainsKey(user))5 d3 X G( ^$ J% Z# W A3 f; t
- CONNECT_POOL.Add(user, socket);//不存在,添加: u4 N* Y* W2 @: ]' }: Y
- else0 T; M4 R/ v. P, o: v, y F+ G) u( [
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新+ }) ^$ _5 G5 G2 D5 \2 L) W r
- CONNECT_POOL[user] = socket;/ q! M! v! l6 h4 C e( a
- #endregion. y& ~( }- x6 n( l& P3 F. J( [. ?
- 8 F, V5 a4 U% f# H. v
- #region 离线消息处理
. T- z; x! ]7 t( Q* g& N a - if (MESSAGE_POOL.ContainsKey(user))
! N E1 ~! m5 M$ \, A7 _ - {0 m4 i/ m% V# |7 o, E( H
- List<MessageInfo> msgs = MESSAGE_POOL[user];$ K- |4 ?+ B9 G6 H4 F( y& E
- foreach (MessageInfo item in msgs) w- m2 G6 ^, q' q _/ y, b3 c
- {0 X0 F- F# L/ l" h" Q
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
' i. |9 t& G$ Q' m4 y" Z - }
+ [, |, g6 H, E- K- o% n3 J - MESSAGE_POOL.Remove(user);//移除离线消息$ L. o$ v( l% x
- }* T9 x" O; h2 r5 P# L
- #endregion
3 Y. v; X7 L5 k8 |) Q# @9 ^
, i% m3 ?& a! B$ Q+ g- string descUser = string.Empty;//目的用户7 m4 C8 t/ i. n: H6 e
- while (true)
# D! o$ {! X- H! G - {; F* W( t' X9 F/ j& K& g4 h" f; D) L5 W
- if (socket.State == WebSocketState.Open)
; v- u" t" \0 z7 Y/ k; y: ` - {; I/ ?, Z8 M, v" P4 `5 V
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);2 F s$ z i! P# {" F) O
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);, k: y. \5 E2 [' r( }1 t4 Y! D
0 }& D0 O% a1 ~8 @8 x- #region 消息处理(字符截取、消息转发)
- x: K: o6 Z! s, W* L - try5 c1 U8 X' a1 ~5 Y+ l
- {: q g1 Y- u5 G* f
- #region 关闭Socket处理,删除连接池
/ o; w0 E) R9 y - if (socket.State != WebSocketState.Open)//连接关闭$ u% d; W, N2 _4 s/ `0 G/ @
- {
: F; P& [) {4 h+ b7 f - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
+ }+ i; @! V d6 Z) w, b - break;1 k& I0 a9 d! N/ [6 Y1 @2 g
- }
! R6 N$ f4 F: d; H8 e0 Y2 w - #endregion# l9 c% `% `( F3 B
4 C6 c) b$ V5 B; A$ T- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息
1 U6 @/ ^9 _/ ~+ m' Z - string[] msgList = userMsg.Split('|');* N5 A+ m( A; n% M
- if (msgList.Length == 2)
5 F$ \; e+ P2 J' W+ V9 |; L - {
% Z H5 @+ B: E# o - if (msgList[0].Trim().Length > 0)5 A0 G7 L% c" i+ Q6 z
- descUser = msgList[0].Trim();//记录消息目的用户
- A' v ?( C6 b1 L. [6 U1 \8 W - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
" a" G& X* b5 Z) c% O5 G - }
3 j; j3 Q" Y' n* D8 [ - else
7 ]3 A# j& K- ]! G3 X' I - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));, m9 c2 R3 V" G' [2 \* ?
- " I$ a3 I, B; ]5 J5 c4 F6 q
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线1 U- a" H& x H0 L" S
- {
9 y1 U& |. Y7 @" c4 \ - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端
4 t8 G" S! [: q+ V! c - if (destSocket != null && destSocket.State == WebSocketState.Open)* p/ W |( ^( s, y$ w* V
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
3 e. ]9 |! x/ s6 v% s - }
e' T; H' k2 q4 y4 m* R9 S - else' q$ s" ~+ |. Z1 l/ X
- {
- ~1 I2 g/ Q5 v; s& F - Task.Run(() =>& r" E2 P; d. W
- {
! v2 g. \$ A. o' U6 H: `. I7 e - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
. n1 V, J) c! @6 z" h - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
0 Z, S! f+ Y# Z6 U7 Y - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息$ O- r% C# L( o. B$ k9 C4 c& {
- });" i: G4 W; _8 r: @' n/ q
- }- c) W7 z# S. R) U( b6 p. o! ]2 [
- }+ D4 C& U9 V2 h, t' q+ X
- catch (Exception exs)) [. l- t% m6 |/ x
- {
% k1 E. d9 K2 w* B5 v2 x" I$ O3 V$ Q7 \ - //消息转发异常处理,本次消息忽略 继续监听接下来的消息
9 u7 q, k J3 }2 e A8 A, d" Z - }# @! t- N# b& W+ \4 ~
- #endregion5 G/ w7 j+ w+ q& d) U, ~# }. \
- }: W8 g0 N9 U! p5 a; T* @
- else
/ p- G) C3 N) a( C - {( w$ e& C$ n: [6 M& X, Y( k8 \
- break;
# U; j# i" M. \2 u; h" J - }
/ l5 \) v2 K8 @% g8 ? - }//while end
! g! R8 Z/ _ N - }+ r% o/ d, l/ B$ {0 x l
- catch (Exception ex). d& e+ p- I9 h2 z- P
- {
# h1 p* R: ]' W6 w' i3 N) H - //整体异常处理
0 o9 x& h/ q: g9 K. w - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);
8 k+ |$ J9 s/ |2 M2 k. [$ N# H I - }
4 c5 |, X! x- {" b - }
( I% X' A5 i3 j, E' v0 ?
6 ?# I# I# |, v- O/ P' ?- ; D; J: Z0 p8 Y) v! r- b
- public bool IsReusable. |$ o% f! c: S+ W! y; D
- {, F8 Y: X9 u) S$ K( r
- get# `' D; G. L! L* i9 B
- {9 [6 A% \; ^2 i/ `0 N1 q
- return false;1 n8 G3 t, O" V* F
- }6 R4 j4 q* C$ f0 e, A( H
- }
* \8 U, N l2 v; ]( o$ T0 k - }5 j/ {5 r/ j% J+ ^
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
7 ]7 G/ X; v2 t# k5 A- q |