服务器端代码编写 1.新建一个ASP.net Web MVC5项目 9 `- q. F. Q. b k/ U" Q
2.新建一个“一般处理程序” 3.Handler1.ashx代码如下: - using System;: O- [' B- G0 r- C2 P
- using System.Collections.Generic;
2 y% P( W/ u, A& v. B - using System.Linq;
8 L) _; G1 L8 k% s* `; S2 G5 u - using System.Net.WebSockets;
( B# H, M8 ?: u: g8 I; u6 q - using System.Text;6 M! S$ c8 U* P: ] n
- using System.Threading;
" q% z" N. i( d9 I0 K# }, D - using System.Threading.Tasks;4 u) l" t9 J0 W/ y+ ~" \
- using System.Web;
, w7 ?# e& g& t v - using System.Web.WebSockets;
+ u4 K, e) X! ~3 U - " }6 d7 W# q/ @* ^
- ; N+ F, S6 F/ [6 S! S; R
- namespace WebApplicationWebsocketHandler: T% z) l9 x' t F
- {9 n! |3 ^7 z$ T, t0 x; O
- /// <summary>
% i1 _/ Z: G1 A# D' ~3 d2 z - /// 离线消息
# A+ m7 P E! ~/ s- S - /// </summary>
6 Q" O( ~! ?! W/ n - public class MessageInfo
' s0 p: k; f( S - {3 [5 n& s7 W+ n- k9 o, P7 w
- public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)
# p) I- Z$ R" Y; ] - {
9 c3 `8 Z5 S( z: r - MsgTime = _MsgTime;
9 ~! D, b: I. k: l2 p - MsgContent = _MsgContent;
" h3 t* a" }5 [3 l/ i. G$ s - }
5 e) R. W9 r2 A5 D& d* G - public DateTime MsgTime { get; set; }- l& @, X5 J2 {: [) R/ C( _
- public ArraySegment<byte> MsgContent { get; set; }
5 ?7 V& X" _0 Y- E; u4 G; D - }
$ r% x7 n' [$ o }6 e# @
9 [/ {) d2 d* t5 Z, G- 1 F- ] P8 z5 K
/ q0 m( E9 {2 {7 y% m
# Z6 _7 k3 c2 v; k6 T9 Y9 E- /// <summary>+ S J! w3 v3 Y( r7 |, ~
- /// Handler1 的摘要说明' t, D6 h. p3 z* V
- /// </summary>8 W8 u, `, u9 { R/ w4 Z+ t* o
- public class Handler1 : IHttpHandler
( S( l+ n/ i* q |% F; B( ` - {
|8 I6 y2 ^6 ^" z1 D& B. _ - private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池+ X0 ?7 e+ X/ ?% r, D9 e8 J% ^ i
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池
( p4 q' }( K: K9 `" C Q - public void ProcessRequest(HttpContext context)
7 J/ ^# a" l) F; ^4 r' C: y" R - {
0 Z, n8 g1 c- v5 l* s7 X" J* } - //context.Response.ContentType = "text/plain";- Z6 L7 `4 }( N
- //context.Response.Write("Hello World");
' K. k2 x3 |2 F' f( O$ F1 x4 Y - if (context.IsWebSocketRequest)/ @% c. G5 T; G- a N, `
- {9 w+ Y2 `2 D. r9 |2 U
- context.AcceptWebSocketRequest(ProcessChat);7 ~ E# T/ \ K M$ [6 O$ u0 R
- }
( Z: P7 Q: K. w, \2 r5 c; j - }
/ M2 I: q6 p0 q; t
3 J6 h5 b7 ^3 E+ K- private async Task ProcessChat(AspNetWebSocketContext context)
% G$ a0 f5 C$ o$ r8 O. g8 I! a3 b6 M - {) D8 `7 W+ N3 m4 V/ i4 P' b
- WebSocket socket = context.WebSocket;
0 P' _1 @3 ]7 Q1 E5 I. a2 V5 Y; s - string user = context.QueryString["user"].ToString();
2 F$ E' h" @3 E2 S8 k: J! _9 M; n - 6 I& x. _& e% ]2 j( x0 m
- try# z9 m5 W8 A o9 s8 p
- {
" S* Q- x% f; b M) V - #region 用户添加连接池
3 f. @. g& g) m2 x5 {4 e - //第一次open时,添加到连接池中
4 x; G9 F( E0 b8 X" D1 u/ w( [ - if (!CONNECT_POOL.ContainsKey(user))
; S5 r8 h' D( H2 ]' I - CONNECT_POOL.Add(user, socket);//不存在,添加% V5 i, E. X, A. e. e" f. l$ N( H
- else n9 Y$ D3 `; ?" B9 C! x) v
- if (socket != CONNECT_POOL[user])//当前对象不一致,更新 p5 ~+ m" g0 T1 h* y; K$ f
- CONNECT_POOL[user] = socket;5 d& [- D- }3 ]- h3 s+ `, b/ _9 o
- #endregion( l3 ]2 u- n6 n
- / s2 K9 G! z: s: M$ a, P9 G
- #region 离线消息处理
0 o7 l' k# a2 l7 f1 B* N - if (MESSAGE_POOL.ContainsKey(user))1 L3 G( Z; c# B/ U0 o& l7 c
- {
' N: N0 n9 K# @. a0 `9 g/ E' T - List<MessageInfo> msgs = MESSAGE_POOL[user];# B: Q* s4 k8 z
- foreach (MessageInfo item in msgs)% Y$ ]. h+ D" ~" E9 g
- {- p; q& y* c, d; P4 i+ y& i
- await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);8 u7 E ~9 O! s7 Q8 \( }
- }% }0 j5 \# ~3 _3 k/ H3 W
- MESSAGE_POOL.Remove(user);//移除离线消息3 I; q2 h/ f! I+ x$ s
- }' j6 w2 }, E( t5 R. i- u( O
- #endregion( E( i: U: E% o0 ?% b6 Q5 X
5 b# j& }5 n: P J1 x0 e- string descUser = string.Empty;//目的用户% n+ K% R1 X; W& J3 \* ^6 a
- while (true)
. N- y7 L3 K3 c* {& s: _ - {' |, [( p- [% W
- if (socket.State == WebSocketState.Open)
( O+ x! B( ]) |8 Z3 f% z - {6 w4 o7 ^& m" f
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);# I& l6 e# _2 G% [* G; o
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);6 r& y& r0 x6 J2 }
- * I2 P0 `+ W' g9 R+ h
- #region 消息处理(字符截取、消息转发)* q- Q2 H% \' @/ P1 G8 W
- try
, Y3 _. Z6 t! h; @# D - {0 o* I; D6 x, N u9 q
- #region 关闭Socket处理,删除连接池
+ q) Q: W! C: E! H4 f- |- K - if (socket.State != WebSocketState.Open)//连接关闭
m" Q) {; f2 h) X* ^% ]* i. \ - {
# T) U$ C7 D7 W a: P - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池3 r: H0 b$ x+ X+ L* Q1 ~
- break;
2 j- \7 K V& B7 u h - }( ?$ s! b3 r/ q
- #endregion
# [8 P+ g" x8 T4 X' v' _4 c3 i1 K - / \! B( U6 J3 j6 Y9 d
- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息+ Q* W! T7 Q) A
- string[] msgList = userMsg.Split('|');
( V: x$ d r6 G - if (msgList.Length == 2)
. f+ k2 j$ n0 {1 o8 q - {
- o, E/ _% j r X1 x; ` - if (msgList[0].Trim().Length > 0)
" N9 p9 a' z& G0 Q7 i7 k0 p - descUser = msgList[0].Trim();//记录消息目的用户+ O) P8 i1 ^$ J. J' @( [; F) S
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
0 m( Y3 q ] G8 I( U - }9 x2 Z: W- |: r% n# F ~
- else
* O3 @' f3 g" ^1 w! A - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));! [: J0 }( s4 Y( d; B+ t
& h. V9 U F& S" g7 s- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线
% g6 N F7 A; Q, ?' i4 D - {
% @' v5 `& M( I# b5 I1 Q6 L - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端0 J8 z5 {: ?* Z+ E
- if (destSocket != null && destSocket.State == WebSocketState.Open)9 q( u+ P) E' m4 ?% n% V1 `
- await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);+ t& W* h8 y$ B
- }1 y% Q! o' _* v2 z
- else
" J& B- o8 D, @ `3 i' n - {3 |# C; K, q' s; t
- Task.Run(() =>
9 I' |% ? i* i' u9 w. d8 Z - {0 L, D$ A e( v9 u8 Y# H
- if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中
2 t' \/ N; o0 W. w7 W1 k - MESSAGE_POOL.Add(descUser, new List<MessageInfo>());
) L/ \2 j( \0 ]2 l4 P' O: r8 N - MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息- ]/ x7 {+ T' l
- });& H h4 \: D3 w& q0 {
- }
7 V) g: q: z4 ^; I+ ` - }
1 k! A1 ]: r9 E: j9 d* F - catch (Exception exs)
9 n/ {9 c0 W8 ? - {+ }. {9 h% H. o( k2 ]' K4 W
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息$ {; C- G4 O. h4 K" B
- }' g7 J: ~$ ^" `# d9 W6 @
- #endregion6 X! K, W7 ?, ~" M
- }
; @$ ]' ~6 h9 ~% p" ^ - else
' O# r; M# h+ |8 C4 s6 y - {
; O) d% }! s" w( b% G7 q - break;$ W& h! p/ O" {6 N
- }
3 D6 d5 g( X) p% K5 W - }//while end: y4 W$ o! x+ O
- }
3 F% s! J0 j$ C/ K1 Q+ r; V) V: T! l - catch (Exception ex)6 k$ k: z0 a; w. k
- {
6 ?* p, k; H4 K - //整体异常处理
" H% p8 _" o9 I/ j - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);5 k( A" P; t7 D V, a$ S, m; h
- }
4 v5 ]& `3 b+ j" x - }
" ?/ ], H/ t7 ? - 0 K2 g D# b/ D7 \
: s6 l' D* S* z0 P7 ^& a& }2 w% A- public bool IsReusable, J: P; [3 e4 t& }4 _
- {) d7 A2 A) F+ V) C3 Z) \
- get
5 Q( Z3 B1 n$ p; G" |1 l f3 _$ G - {& {* {2 w# ]4 Y- Z1 W h
- return false;
$ R- E1 q6 b" F9 T" H0 R+ H1 a - }" O/ x# N! @7 Y ]3 s" C
- }9 a1 } e& v/ I4 H+ k2 o: A* h5 t
- }
& C3 Z. o5 V; `7 B; W* i - }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上 点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径 2 Z) U; U% E) s( {) Y- i
|