上一篇文章,我们了解了客户端如何与服务器创建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", 2012)) { //设置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, 1000, 1000);
这样 所有与服务端保持连接的客户端就都可以接受到来自服务器端的消息了。
在这个例子里 我们看到了所有的消息都是由会话对象发出的,会话对象Send的消息 也支持“文本”与“二进制两种形式,同时会话对象还提供一个SendCloseHandshakeResponse()方法向客户端发送一个强制断开连接的指令。
WebSocketSession对象包含了服务端和客户端的所有信息,以及WebSocketServer对象本身,我们可以利用它做很多事情,下边我们就来实现一个简单的聊天室。至于聊天室的原理 就是一个人将要说的话发送到服务器,再由服务器广播给在这个聊天室里的所有人看到。恩 就这么简单。我们来上代码,多了不解释,相当简单。
public class ChatWebSocket { private const string ip = "127.0.0.1"; private const int port = 2014; 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字符串类型数据的处理
示例代码在这里 下载