一步一步学WebSocket(二) 使用SuperWebSocket实现自己的服务端
上一篇文章,我们了解了客户端如何与服务器创建WebSocket连接。但是一个巴掌拍不响,既然是通信,就必然最少要有两个端。今天我们来看看c#如何用已有的框架实现一个WebSocket服务端。
在.Net Framework 4.5及以上版本中,微软为我们集成了WebSocket协议的基本实现。微软提供的WebSocket对象位于System.Net.WebSocket命名空间下,使用起来挺繁琐的,所以我选择了SuperWebSocket框架来简化开发的难度。
SuperWebSocket框架可以通过NuGet直接获取并引用到项目中,也可以在http://superwebsocket.codeplex.com/中下载最新的DLL
我们来看SuperWebSocket如何我们快速搭建一个服务端
- WebSocketServer wsServer = new WebSocketServer();
- if (!wsServer.Setup("127.0.0.1", ))
- {
- //设置IP 与 端口失败 通常是IP 和端口范围不对引起的 IPV4 IPV6
- }
- if (!wsServer.Start())
- {
- //开启服务失败 基本上是端口被占用或者被 某杀毒软件拦截造成的
- return;
- }
- wsServer.NewSessionConnected += (session) =>
- {
- //有新的连接
- };
- wsServer.SessionClosed += (session, reason) =>
- {
- //有断开的连接
- };
- wsServer.NewMessageReceived += (session, message) =>
- {
- //接收到新的文本消息
- };
- wsServer.NewDataReceived += (session, bytes) =>
- {
- //接收到新的二进制消息
- };
- Console.ReadKey();
- wsServer.Stop();
这里WebSocketServer对象通过Setup方式对要侦听的IP及端口进行了设置。然后使用Start方法启动侦听。
Setup方法有4种重载,但是我们通常用到的只有设置IP和端口,IP为string类型,如果传入的字符串无法被转换为支持的IP格式,Setup方法会返回false表示设置失败。
WebSocketServer还提供了4个事件用以管理与客户端的连接、断开、和接受消息动作。新版本的WebSocket支持传送的数据格式有 “文本” 和 “二进制”两种,NewMessageReceived事件用于处理文本类型的消息,NewDataReceived事件用于处理二进制类型的消息。
到这里 我们已经成功的搭建了一个实现了WebSocket协议的服务端了。至于服务端的寄宿方式有很多,SuperWebSocket框架支持以 控制台、Winform、IIS以及Windows服务的形式寄宿服务,不过网上很多资料都不建议在IIS中寄宿服务,据说是因为寄宿在IIS中性能比较低。
WebSocket既然是双工通信,那么我们就不能光等着接收来自客户端的消息, 我们也需要从服务端向客户端“推送”消息,现在我们来看如何由服务端向客户端发送消息。
SuperWebSocket框架中,服务端与客户端创建的连接对象为WebSocketSession类型,也就是说它将每一个客户端的实例视为一个会话,在客户端创建连接的时候,产生这个会话,在客户端断开连接的时候,销毁这个会话,而客户端与服务端进行消息通信的时候,也依赖这个会话进行传递。我们要实现服务器端向客户端的广播,就要获取到当前正在活动的所有会话,我们通过代码来看如何获取所有的会话
- wsServer.GetAllSessions() //获取所有的会话 已断开的会话不会出现在集合中
很简单吧,在获取到活动的会话之后 我们就可以向客户端发送消息了,这里我们让服务器向客户端定时发送服务器时间
- Timer timer = new Timer((data) =>
- {
- var msg = string.Format("服务器当前时间:{0:HH:MM:ss}", DateTime.Now);
- //对当前已连接的所有会话进行广播
- foreach (var session in wsServer.GetAllSessions())
- {
- session.Send(msg);
- }
- }, null, , );
这样 所有与服务端保持连接的客户端就都可以接受到来自服务器端的消息了。
在这个例子里 我们看到了所有的消息都是由会话对象发出的,会话对象Send的消息 也支持“文本”与“二进制两种形式,同时会话对象还提供一个SendCloseHandshakeResponse()方法向客户端发送一个强制断开连接的指令。
WebSocketSession对象包含了服务端和客户端的所有信息,以及WebSocketServer对象本身,我们可以利用它做很多事情,下边我们就来实现一个简单的聊天室。至于聊天室的原理 就是一个人将要说的话发送到服务器,再由服务器广播给在这个聊天室里的所有人看到。恩 就这么简单。我们来上代码,多了不解释,相当简单。
- public class ChatWebSocket
- {
- private const string ip = "127.0.0.1";
- private const int port = ;
- private WebSocketServer ws = null;//SuperWebSocket中的WebSocketServer对象
- public ChatWebSocket()
- {
- ws = new WebSocketServer();//实例化WebSocketServer
- //添加事件侦听
- ws.NewSessionConnected += ws_NewSessionConnected;//有新会话握手并连接成功
- ws.SessionClosed += ws_SessionClosed;//有会话被关闭 可能是服务端关闭 也可能是客户端关闭
- ws.NewMessageReceived += ws_NewMessageReceived;//有客户端发送新的消息
- }
- void ws_NewSessionConnected(WebSocketSession session)
- {
- Console.WriteLine("{0:HH:MM:ss} 与客户端:{1}创建新会话", DateTime.Now, GetSessionName(session));
- var msg = string.Format("{0:HH:MM:ss} {1} 进入聊天室", DateTime.Now, GetSessionName(session));
- SendToAll(session, msg);
- }
- void ws_SessionClosed(WebSocketSession session, SuperSocket.SocketBase.CloseReason value)
- {
- Console.WriteLine("{0:HH:MM:ss} 与客户端:{1}的会话被关闭 原因:{2}", DateTime.Now, GetSessionName(session), value);
- var msg = string.Format("{0:HH:MM:ss} {1} 离开聊天室", DateTime.Now, GetSessionName(session));
- SendToAll(session, msg);
- }
- void ws_NewMessageReceived(WebSocketSession session, string value)
- {
- var msg = string.Format("{0:HH:MM:ss} {1}说: {2}", DateTime.Now, GetSessionName(session), value);
- SendToAll(session, msg);
- }
- /// <summary>
- /// 启动服务
- /// </summary>
- /// <returns></returns>
- public void Start()
- {
- if (!ws.Setup(ip, port))
- {
- Console.WriteLine("ChatWebSocket 设置WebSocket服务侦听地址失败");
- return;
- }
- if (!ws.Start())
- {
- Console.WriteLine("ChatWebSocket 启动WebSocket服务侦听失败");
- return;
- }
- Console.WriteLine("ChatWebSocket 启动服务成功");
- }
- /// <summary>
- /// 停止侦听服务
- /// </summary>
- public void Stop()
- {
- if (ws != null)
- {
- ws.Stop();
- }
- }
- private string GetSessionName(WebSocketSession session)
- {
- //这里用Path来取Name 不太科学……
- return HttpUtility.UrlDecode(session.Path.TrimStart('/'));
- }
- private void SendToAll(WebSocketSession session, string msg)
- {
- //广播
- foreach (var sendSession in session.AppServer.GetAllSessions())
- {
- sendSession.Send(msg);
- }
- }
- }
关与SuperWebSocket的基本使用就介绍到这里了……顶着老板不时窥屏的压力,可能文章有点语无伦次,希望大家多多体谅,也希望大家提出宝贵意见 共同学习。下一篇我会考虑介绍“子协议”和SuperWebSocket提供的Json字符串类型数据的处理
示例代码在这里 下载
提示:
SuperSocket与SuperWebSocket框架都是Kerry Jiang的项目 SuperSocket最新版本号是1.6 SuperWebSocket最新版本号是0.8 之前一直以为第一个是官网的……后来查了下资料不是……第一个框架BUG海多……这里给大家提个醒……
本系列本月暂停更新………这个框架资料很少……而且有点坑……在死磕探路中……
一步一步学WebSocket(二) 使用SuperWebSocket实现自己的服务端的更多相关文章
- hbase源码系列(十二)Get、Scan在服务端是如何处理
hbase源码系列(十二)Get.Scan在服务端是如何处理? 继上一篇讲了Put和Delete之后,这一篇我们讲Get和Scan, 因为我发现这两个操作几乎是一样的过程,就像之前的Put和Del ...
- WebSocket安卓客户端实现详解(三)–服务端主动通知
WebSocket安卓客户端实现详解(三)–服务端主动通知 本篇依旧是接着上一篇继续扩展,还没看过之前博客的小伙伴,这里附上前几篇地址 WebSocket安卓客户端实现详解(一)–连接建立与重连 We ...
- hbase源码系列(十二)Get、Scan在服务端是如何处理?
继上一篇讲了Put和Delete之后,这一篇我们讲Get和Scan, 因为我发现这两个操作几乎是一样的过程,就像之前的Put和Delete一样,上一篇我本来只打算写Put的,结果发现Delete也可以 ...
- Nacos(二)源码分析Nacos服务端注册示例流程
上回我们讲解了客户端配置好nacos后,是如何进行注册到服务器的,那我们今天来讲解一下服务器端接收到注册实例请求后会做怎么样的处理. 首先还是把博主画的源码分析图例发一下,让大家对整个流程有一个大概的 ...
- 阶段5 3.微服务项目【学成在线】_day01 搭建环境 CMS服务端开发_01-项目概述-功能构架-项目背景
这个就是博学谷下的 在线教育平台
- Demo源码放送:打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...
- 打通B/S与C/S !让HTML5 WebSocket与.NET Socket公用同一个服务端!
随着HTML5 WebSocket技术的日益成熟与普及,我们可以借助WebSocket来更加方便地打通BS与CS -- 因为B/S中的WebSocket可以直接连接到C/S的服务端,并进行双向通信.如 ...
- 一步一步跟我学DeviceOne开发 - 仿微信应用(一,二,三)
这是一个系列的文档,长期目标是利用DeviceOne开发一些目前使用广泛的优质手机应用,我们会最大化的实现这些应用的每一个功能和细节,不只停留在简单的UI模仿和Demo阶段,而是一个基本可以使用的实际 ...
- usb-host一步一步学(二)安卓在usb-host模式下列出当前连接的usb设备
之前写了一个简单的例子usb-host一步一步学(一)安卓在usb-host模式下列出当前连接的usb设备,下面的这个例子是获取各种usb设备.usb接口以及usb连接点(endpoint) 正如上一 ...
随机推荐
- [MySQL] 号称永久解决了复制延迟问题的并行复制,MySQL5.7
一.缘由: 某天看到主从复制延时的告警有点频繁,就想着是不是彻底可以解决一下. 一般主从复制,有三个线程参与,都是单线程:Binlog Dump(主) ----->IO Thread (从) - ...
- php 对象中连贯执行方法
连贯操作的重点是返回当前对象,以便可以继续执行 class Ceshi{ public $str = ''; public function f1($a){ $this->str .= $a; ...
- HDFS snapshot操作实战
Hadoop从2.1.0版开始提供了HDFS SnapShot的功能.一个snapshot(快照)是一个全部文件系统.或者某个目录在某一时刻的镜像.快照在下面场景下是非常有用:防止用户的错误操作:管理 ...
- [HDU 4336] Card Collector (状态压缩概率dp)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4336 题目大意:有n种卡片,需要吃零食收集,打开零食,出现第i种卡片的概率是p[i],也有可能不出现卡 ...
- delphi.thread.线程循环执行体结构
线程话题太大,又都是些坑,不知从哪方面讲起,所以,想一出是一出了. 不管怎样,我们从开始使用D,不管有没有用线程,其实它已经帮我们做了一个最完整的线程执行处理:Application.Run. 这行A ...
- Java 2D API - 1. 基本概念
Java 2D API扩展AWT包,对二维图形.文本及成像功能提供了支持,可用于开发复杂的界面.绘图软件和图像编辑器.Java 2D对象位于用户坐标空间(User coordinate space), ...
- 用world写blog
一级目录 怎么写呢? 这个和markdown那个更加方便呢? 据说插入表格有问题 我试一试 二级目录 这个大小还不错 添加第三季目录呢 三级目录 添加目录必须要用鼠标么? #inclu ...
- 使用spring通知时,代理出错
动态代理是基于接口的,spring配置是基于类的!!!!!!!!!! 注意:JDK的动态代理,只能对实现接口的类实现代理,生成代理对象,如果这个类没有实现接口,是生成不了代理对象的.如本例UserMa ...
- phthon
没什么特别的,我们项目的跨平台代码都是在Windows环境下编码,然后跨平台编译调试,C++和Python代码都是如此.我们用C++实现底层和框架,用ctypes将纯C的API给Python化,然后用 ...
- shell 脚本,提取文件中的内容
使用awk.cut.sed.if.while 等 awk.cut.sed还是很重要的 这是后来修改的,可以完成 #!/bin/bash #conver formatFILE=mobile_dpi.ru ...