cncml手绘网
标题: 在IIS上搭建WebSocket服务器(二) [打印本页]
作者: admin 时间: 2018-11-7 00:43
标题: 在IIS上搭建WebSocket服务器(二)
服务器端代码编写
1.新建一个ASP.net Web MVC5项目
: l4 e, l/ {& g6 y( m2.新建一个“一般处理程序”
3.Handler1.ashx代码如下:
- using System;
) M4 W) p/ k9 B1 m - using System.Collections.Generic; Q7 ] G1 y2 D6 M! Y u
- using System.Linq;' J1 m% X( ^2 u y. b6 D
- using System.Net.WebSockets;
r, u1 H7 T. I7 ~, y+ `+ g3 S0 o - using System.Text;
% |# ~; g( y- @4 t X T - using System.Threading;+ c' O% h: _' o3 N$ n( D; P5 A$ y# X
- using System.Threading.Tasks;
2 z( ]1 m$ U' z; ] - using System.Web;$ _5 f: E/ g- Q/ b9 x6 F3 j
- using System.Web.WebSockets;
) `1 I& ` A( H- h) J* M0 M9 r6 o - 8 ?& j) W0 J: M* h5 R
! B/ L O: c: |- namespace WebApplicationWebsocketHandler
' }* X# K) `7 R7 i+ h! y - {
! `' S) s8 N, u! O: ^+ E" V - /// <summary>/ m. d! F4 Y% h& q) p& {, s2 y
- /// 离线消息7 I/ `( T) R. Q9 g* A9 n5 T
- /// </summary>' R4 J e& N2 j4 U6 M3 _, h
- public class MessageInfo
/ X& x% j7 h g( J - {
5 p, }. o# N, B5 W6 t0 s" p% s5 W! { - public MessageInfo(DateTime _MsgTime, ArraySegment<byte> _MsgContent)9 f1 T" l2 |0 b
- {0 ^( N2 K) p( b3 z) F5 J
- MsgTime = _MsgTime;) l( ?4 C7 n# ^6 E
- MsgContent = _MsgContent;
' x9 q% f# y! g* Y/ A$ y - }
4 x' C' m! f2 n. j9 I3 J - public DateTime MsgTime { get; set; }
5 x4 f% B9 P# j* k/ d - public ArraySegment<byte> MsgContent { get; set; }
; h" e3 j2 S' I3 s( E/ k8 T1 I - }
9 o, k- v* s3 B! O6 A2 o
5 b1 [/ `# [/ y1 C( N6 e- , ^9 b% |8 y* ?$ W+ {$ s) f
- ; `5 l6 M3 r7 X5 ~
; G. q/ j* D8 [# M0 [- /// <summary>: j9 x) \' d' a
- /// Handler1 的摘要说明
! {$ I8 E6 h0 U% l% n+ u - /// </summary>7 V# Q/ D' V; ]9 t5 y
- public class Handler1 : IHttpHandler
9 T, j/ k3 |" L - {4 J8 t d# S! z% k2 q. B5 G
- private static Dictionary<string, WebSocket> CONNECT_POOL = new Dictionary<string, WebSocket>();//用户连接池/ ~9 d4 w# P b8 x
- private static Dictionary<string, List<MessageInfo>> MESSAGE_POOL = new Dictionary<string, List<MessageInfo>>();//离线消息池" U# ~$ C1 ?1 Z
- public void ProcessRequest(HttpContext context)$ [5 R. a* D b
- {
# a- F% p N( v; t) x2 l - //context.Response.ContentType = "text/plain";, f% `9 d% ^' ~2 @: O
- //context.Response.Write("Hello World");
2 [) I0 T: ^" `3 h2 a - if (context.IsWebSocketRequest) h7 C; Q) T$ M7 `) N! y( {! G% ^
- {4 }+ d0 R* h5 n4 G# }$ ?8 b
- context.AcceptWebSocketRequest(ProcessChat);) @" D. I% D# [8 _
- }
" S0 f! m) N# D8 {- G+ o - }9 U0 l$ n( x& F8 A
- 5 d9 i. Z' y$ N4 |
- private async Task ProcessChat(AspNetWebSocketContext context)2 ^6 j9 o u9 J: q1 u! ^/ G
- {
! s; C2 k# h6 C! u: T% A3 g2 W5 `# F - WebSocket socket = context.WebSocket;
$ t- ~ E6 W O8 n5 `; Y - string user = context.QueryString["user"].ToString();
) N. i5 ]$ r+ R; H; ~, I5 e) w8 w! D
* m( [. h8 @, ~- try' ` s2 J4 _) b0 A
- {
: Z5 L+ U7 W$ K0 E - #region 用户添加连接池
4 K1 Z: r9 I% k+ p0 U# F1 [ - //第一次open时,添加到连接池中
1 @, ]4 n) J( }0 D5 i - if (!CONNECT_POOL.ContainsKey(user))
4 Z( o) f8 n5 @ - CONNECT_POOL.Add(user, socket);//不存在,添加
2 h2 l% d7 t# I - else
5 z5 K+ h, x- R& r7 D( F - if (socket != CONNECT_POOL[user])//当前对象不一致,更新0 l7 B3 \# X& l, H+ K9 }
- CONNECT_POOL[user] = socket;3 @* O2 {, t9 i, }* W% \. b
- #endregion1 h+ K) j K8 v, _! @
- 1 l. B |% j& m# P2 \
- #region 离线消息处理
; C! x9 X. i" V$ [ - if (MESSAGE_POOL.ContainsKey(user))& Y! ]% Z2 Z" [2 w3 k
- {
q) {/ |& k% j5 {0 A5 {1 B7 _ - List<MessageInfo> msgs = MESSAGE_POOL[user];
2 `4 d* D& ?1 T- c6 [1 T - foreach (MessageInfo item in msgs)
7 W8 c' ?7 @/ h( |) B - {
! v6 \; Y3 i& u! S - await socket.SendAsync(item.MsgContent, WebSocketMessageType.Text, true, CancellationToken.None);
7 l5 m+ p* H m7 W+ A: T# b8 ?- v - }0 \- g, z3 M/ b l, W2 f* a
- MESSAGE_POOL.Remove(user);//移除离线消息
: t. i/ Q! @7 G/ q. \5 B - }
3 D* X) d+ W6 p( i7 a2 r - #endregion8 [0 |% O- H. A! @
- 0 ^+ `" m9 z2 A: A3 k' U
- string descUser = string.Empty;//目的用户
" V" ]: R; _/ _; W- M0 z. ] - while (true)
1 Z) J* R. d+ {5 q* N2 P5 ` - {! I' d& a" l$ u b1 b' \0 M5 P
- if (socket.State == WebSocketState.Open)) i/ T/ O! e- r* N, [! u
- {. W6 ?* C0 J0 F0 c% M
- ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[2048]);& M/ e2 V- b- X, n/ p1 K
- WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None);
% v' U: j H+ v3 i! n
. N! D0 X* @1 i% A: E* [( ]! r- #region 消息处理(字符截取、消息转发)* \2 j; Y; Y o
- try
+ K# D& T- g0 { - {
& b4 v$ d; J% P! O - #region 关闭Socket处理,删除连接池4 e2 p: ?9 E# r2 {4 B. u; m
- if (socket.State != WebSocketState.Open)//连接关闭, R5 ?. L/ n# H2 `9 x X
- {
3 D+ y- i' Y$ o* v% {3 C - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);//删除连接池
/ q6 W5 N( m+ T i& d - break;, B) q- q( f" t5 w% V2 m( }: J
- }9 Y$ s2 `2 c; d
- #endregion6 F6 v, V: W" J7 u l q2 x; Z: ?
9 b, v, R4 W# o, e- string userMsg = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);//发送过来的消息9 q8 y* ~, U! [4 i
- string[] msgList = userMsg.Split('|');. g f& ?* k& l! {9 ]
- if (msgList.Length == 2)% H0 t. [0 M; D% s
- {
7 d) y+ k5 K9 d- r. D/ z( U, _ - if (msgList[0].Trim().Length > 0)
: l# B! e# U$ d( p U6 [3 j - descUser = msgList[0].Trim();//记录消息目的用户
; N2 M* `) S$ X) S& _, j - buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(msgList[1]));
" e; Z# g. C `: r, |" r - }0 j) ?9 U3 } _6 M2 {, c
- else: Q; b" a& @" ~( o( D0 l
- buffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMsg));
1 U6 W/ @4 }! _8 R5 I- V) w - . P& d# `" k! C- W. v% C
- if (CONNECT_POOL.ContainsKey(descUser))//判断客户端是否在线8 d' Q0 {$ V. T- w5 Q
- {
4 g9 t& G: x+ L: } - WebSocket destSocket = CONNECT_POOL[descUser];//目的客户端' D* v! G: ?3 c+ [* E/ V% o
- if (destSocket != null && destSocket.State == WebSocketState.Open)
. A4 I: q- {$ }8 u ]6 ~% p - await destSocket.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);8 Z, ?" f7 T( }$ V- K: ]
- }% U! W2 e: R; M( x4 O
- else1 s$ f( t! P4 o; i) ^
- {
$ O# J- Z, E w I - Task.Run(() =>+ r. O5 N' Y+ j! @4 R
- {
0 k( I7 L" D7 h* C9 W7 X8 Z - if (!MESSAGE_POOL.ContainsKey(descUser))//将用户添加至离线消息池中+ M3 m4 x/ g/ x# Z! z8 Q2 W! K+ G
- MESSAGE_POOL.Add(descUser, new List<MessageInfo>());" ^1 W" u/ i2 h2 @' H
- MESSAGE_POOL[descUser].Add(new MessageInfo(DateTime.Now, buffer));//添加离线消息
v; h) x0 z: h3 l - });* M; ~% `' ^5 j
- }
: W3 z& I* m2 a* |2 z5 X - }
" A. {' g- n7 ]" o$ R+ k# B3 \ - catch (Exception exs)1 C2 M* `2 j0 B9 s" Y- b. W
- {7 H! S3 a+ D9 ]" |% i' T
- //消息转发异常处理,本次消息忽略 继续监听接下来的消息
* W2 W9 }( r) r6 F - }
y% ?/ W. G& m0 i) Y( X; n- i/ A; B - #endregion- f5 o0 t/ f' L( A! e5 g! \" K* Z3 r
- }5 }: H: k! t# h8 d4 |; A$ a, U
- else8 \ ^/ M& r- K+ \" O
- {- F+ }: N( n1 w( i
- break;: G8 S! u" Y0 z- i0 U2 d2 Y3 |
- }$ P! d# \! T0 H
- }//while end
/ k; T$ r+ d" ?$ P - }
+ V) b; D2 d5 [. W7 \) Z, | - catch (Exception ex)+ L8 i! j6 A3 l1 ~) m. d
- {
+ b: E. [3 m$ ?. F( H+ m' | - //整体异常处理
* Z1 A3 i# |' ^ - if (CONNECT_POOL.ContainsKey(user)) CONNECT_POOL.Remove(user);! x, o! S" }4 N7 @3 s
- }
/ ^$ H$ C' w5 x) o - }
5 [* l/ J' M9 @9 @! s$ ` - * c: {. y& V$ c+ q( j
# m# M( i1 A6 K- public bool IsReusable# o6 v( q$ d# O. t/ E7 [+ `: ]
- {
6 t- H! ~, d% `( M" {( T8 Z+ D - get
6 ^4 V& q3 G$ W' ^ - {
+ ?4 O1 k4 [# y1 G - return false;( M0 X7 I+ h2 \4 Y: [
- }0 L+ T5 Y- x: t, n3 C/ [7 b
- }0 L; k$ e7 f: X9 m4 I, w
- }, y. ~, b: ]! g; g( P8 r
- }
复制代码4.运行看是否报错,若没错将我们的服务器网站发布到IIS(支持WebSocket的IIS上,win7的系统时不可以的)上
点击“生成”->"发布........",以文件系统的方式发布,目标位置为我们创建的IIS网站对应的物理路径
% k- T0 [( P* |+ X
| 欢迎光临 cncml手绘网 (http://bbs.cncml.com/) |
Powered by Discuz! X3.2 |