用C# ASP.NET MVC 实现WebSocket ,对于WebSocket想必都很了解了,不多说.

东西做的很粗糙 只能实现基本的聊天功能,不过基本的通信实现了,那么后序的扩展应该也不难(个人这么认为...)

先看下效果

可同时支持群聊和私聊 源码下载地址

http://download.csdn.net/detail/formularz/4668280

首先介绍下ValueWebSocket.cs 这个文件 主要是对与客户端的通信进行集中控制

1.ValueServer: Socket服务端

2.ValueProtocol:对WebSocket通信的数据加以解析

3.SessionManager: 集中管理在线用户

ValueWebSocket.cs

  
ValueWebSocket.cs
  public class ValueWebSocket
     {         // WebSocket服务端
         private ValueServer server;
         // 解析协议
         private ValueProtocol valueProtocol;
         // 管理在线用户
         private SessionManager sessionManager;

         public ValueWebSocket(String ipAddress, Int32 port)
         {             valueProtocol = new ValueProtocol();
             sessionManager = new SessionManager();

             server = new ValueServer(ipAddress, port, Encoding.UTF8);
             server.OnReceive += new ValueHelper.ValueSocket.Infrastructure.ReceiveHandler(server_OnReceive);
         }

         private void server_OnReceive(ValueHelper.ValueSocket.SocketEvents.ReceiveEventArgs e)
         {             // 分析用户是否已存在
             if (sessionManager.CheckSessionExist(e.Socket))
             {                 Message message = valueProtocol.Decode(e.Data);
                 if (message.header.Opcode == OperType.Close)
                 {                     removeUser(e.Socket);
                 }
                 if (message.header.Opcode == OperType.Text)
                 {                     String msg = message.Data.ToString();
                     execMsg(e.Socket, msg);
                 }
             }
             else
             {                 // 用户不存在则添加用户
                 // 并发送握手信息与客户端建立连接
                 String request = Encoding.UTF8.GetString(e.Data);
                 Byte[] response = valueProtocol.GetResponse(request);
                 server.Send(e.Socket, response);
                 sessionManager.AddSession(e.Socket, request);
             }
         }

         // 对消息进行的处理
         private void execMsg(Socket socket, String message)
         {             String name = String.Empty;
             foreach (ValueSession session in SessionManager.Sessions)
             {                 Socket sk = session.Socket;
                 if (sk.Connected)
                 {                     if (sk.RemoteEndPoint == socket.RemoteEndPoint)
                     {                         name = session.Cookies["name"];
                         break;
                     }
                 }
             }

             // 判断私聊还是公共
             String[] separator = message.Split(new String[] { "<separator>" }, StringSplitOptions.None);
             String msg = String.Concat(name, ": ", separator[1]);
             if (separator[0] == "All")
                 SendToAll(msg);
             else
             {                 foreach (ValueSession session in SessionManager.Sessions)
                 {                     if (session.Cookies["name"] == separator[0])
                     {                         sendTo(session.Socket, msg);
                         break;
                     }
                 }
             }
         }

         private void removeUser(Socket socket)
         {             sessionManager.RemoveSession(socket);
         }

         private void SendToAll(String msg)
         {             foreach (ValueSession session in SessionManager.Sessions)
             {                 sendTo(session.Socket, msg);
             }
         }

         private Boolean sendTo(Socket socket, String msg)
         {             Byte[] data = valueProtocol.Encode(msg);
             return server.Send(socket, data);
         }

         public void Start()
         {             server.Start();
         }

         public void Dispose()
         {             sessionManager.Dispose();
             server.Dispose();
         }
     }

SessionManager: 该类就不多说了,集中管理用户类.详情查看源码.

ValueProtocol: 这个类其实只是一个接口类,

真正对数据进行解析的是ProtocolDraft10类(按草案10中介绍的规则对数据进行解析,注:对协议说明有兴趣的同学可以查看这位大牛的文章http://blog.csdn.net/fenglibing/article/details/6852497)

ProtocolDraft10.cs

  
ProtocolDraft10.cs
  public class ProtocolDraft10 : IProtocol
     {         private const String WebSocketKeyPattern = @"Sec\-WebSocket\-Key:\s+(?<key>.*)\r\n";
         private const String MagicKey = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
         private const Char charOne = '1';
         private const Char charZero = '0';

         #region Handshake

         // 发送回复信息完成握手
         public Byte[] ProduceResponse(string request)
         {             String webSocketKey = Common.GetRegexValue(request, WebSocketKeyPattern)[0].Groups["key"].Value;
             String acceptKey = produceAcceptKey(webSocketKey);
             StringBuilder stringBuilder = new StringBuilder();
             stringBuilder.Append(String.Concat("HTTP/1.1 101 Web Socket Protocol Handshake", Environment.NewLine));
             stringBuilder.Append(String.Concat("Upgrade: WebSocket", Environment.NewLine));
             stringBuilder.Append(String.Concat("Connection: Upgrade", Environment.NewLine));
             stringBuilder.Append(String.Concat("Sec-WebSocket-Accept: ", acceptKey, Environment.NewLine, Environment.NewLine));
             String asd = stringBuilder.ToString();
             return Encoding.UTF8.GetBytes(stringBuilder.ToString());
         }
         // 根据Sec-WebSocket-Key和MagicKey生成AcceptKey
         private String produceAcceptKey(String webSocketKey)
         {             Byte[] acceptKey = SHA1.Create().ComputeHash(Encoding.ASCII.GetBytes(webSocketKey + MagicKey));
             return Convert.ToBase64String(acceptKey);
         }

         #endregion

         #region Decode
         // 对客户端发来的数据进行解析
         public Message Decode(Byte[] data)
         {             Byte[] buffer = new Byte[14];
             if (data.Length >= 14)
                 Buffer.BlockCopy(data, 0, buffer, 0, 14);
             else
                 Buffer.BlockCopy(data, 0, buffer, 0, data.Length);
             MessageHeader header = analyseHead(buffer);
             Message msg = new Message();
             msg.header = header;

             Byte[] payload;
             if (header != null)
             {                 payload = new Byte[data.Length - header.PayloadDataStartIndex];
                 Buffer.BlockCopy(data, header.PayloadDataStartIndex, payload, 0, payload.Length);
                 if (header.MASK == charOne)
                 {                     for (int i = 0; i < payload.Length; i++)
                     {                         payload[i] = (Byte)(payload[i] ^ header.Maskey[i % 4]);
                     }
                 }
             }
             else
             {                 msg.Data = Encoding.UTF8.GetString(data);
                 return msg;
             }

             if (header.Opcode == OperType.Text)
                 msg.Data = Encoding.UTF8.GetString(payload);

             return msg;
         }
         private MessageHeader analyseHead(Byte[] buffer)
         {             MessageHeader header = new MessageHeader();
             header.FIN = (buffer[0] & 0x80) == 0x80 ? charOne : charZero;
             header.RSV1 = (buffer[0] & 0x40) == 0x40 ? charOne : charZero;
             header.RSV2 = (buffer[0] & 0x20) == 0x20 ? charOne : charZero;
             header.RSV3 = (buffer[0] & 0x10) == 0x10 ? charOne : charZero;

             if ((buffer[0] & 0xA) == 0xA)
                 header.Opcode = OperType.Pong;
             else if ((buffer[0] & 0x9) == 0x9)
                 header.Opcode = OperType.Ping;
             else if ((buffer[0] & 0x8) == 0x8)
                 header.Opcode = OperType.Close;
             else if ((buffer[0] & 0x2) == 0x2)
                 header.Opcode = OperType.Binary;
             else if ((buffer[0] & 0x1) == 0x1)
                 header.Opcode = OperType.Text;
             else if ((buffer[0] & 0x0) == 0x0)
                 header.Opcode = OperType.Row;

             header.MASK = (buffer[1] & 0x80) == 0x80 ? charOne : charZero;
             Int32 len = buffer[1] & 0x7F;
             if (len == 126)
             {                 header.Payloadlen = (UInt16)(buffer[2] << 8 | buffer[3]);
                 if (header.MASK == charOne)
                 {                     header.Maskey = new Byte[4];
                     Buffer.BlockCopy(buffer, 4, header.Maskey, 0, 4);
                     header.PayloadDataStartIndex = 8;
                 }
                 else
                     header.PayloadDataStartIndex = 4;
             }
             else if (len == 127)
             {                 Byte[] byteLen = new Byte[8];
                 Buffer.BlockCopy(buffer, 4, byteLen, 0, 8);
                 header.Payloadlen = BitConverter.ToUInt64(byteLen, 0);
                 if (header.MASK == charOne)
                 {                     header.Maskey = new Byte[4];
                     Buffer.BlockCopy(buffer, 10, header.Maskey, 0, 4);
                     header.PayloadDataStartIndex = 14;
                 }
                 else
                     header.PayloadDataStartIndex = 10;
             }
             else
             {                 if (header.MASK == charOne)
                 {                     header.Maskey = new Byte[4];
                     Buffer.BlockCopy(buffer, 2, header.Maskey, 0, 4);
                     header.PayloadDataStartIndex = 6;
                 }
                 else
                     header.PayloadDataStartIndex = 2;
             }
             return header;
         }

         #endregion

         #region Encode
         // 对要发送的数据进行编码一符合草案10的规则
         public Byte[] Encode(String msg)
         {             Byte[] data = Encoding.UTF8.GetBytes(msg);
             Int32 dataLength = data.Length;

             Byte[] head = packetHeader(OperType.Text, dataLength);
             for (int i = 0; i < data.Length; i++)
             {                 data[i] = (Byte)(data[i] ^ maskKey[i % 4]);
             }

             Byte[] result = new Byte[head.Length + dataLength];
             Buffer.BlockCopy(head, 0, result, 0, head.Length);
             Buffer.BlockCopy(data, 0, result, head.Length, dataLength);
             return result;
         }
         private const Byte byte80 = 0x80;
         private Byte[] maskKey = new Byte[] { 113, 105, 97, 110 };
         private Byte[] packetHeader(OperType operType, Int32 length)
         {             Byte byteHead = (Byte)(byte80 | (Byte)operType);
             Byte[] byteLen;
             if (length < 126)
             {                 byteLen = new Byte[1];
                 byteLen[0] = (Byte)(byte80 | (Byte)length);
             }
             else if (length < 65535)
             {                 byteLen = new Byte[3];
                 byteLen[0] = (Byte)(byte80 | (Byte)126);
                 for (int i = 1; i < 3; i++)
                     byteLen[i] = (Byte)(length >> (8 * (2 - i)));
             }
             else
             {                 byteLen = new Byte[9];
                 byteLen[0] = (Byte)(byte80 | (Byte)127);
                 for (int i = 1; i < 9; i++)
                     byteLen[i] = (Byte)(length >> (8 * (8 - i)));
             }

             Byte[] packet = new Byte[1 + byteLen.Length + maskKey.Length];
             packet[0] = byteHead;
             Buffer.BlockCopy(byteLen, 0, packet, 1, byteLen.Length);
             Buffer.BlockCopy(maskKey, 0, packet, 1 + byteLen.Length, maskKey.Length);
             return packet;
         }

         #endregion
     }

改类主要实现与客户端的握手级数据的解析,至于为什么这么解析,可访问上面那位大牛的文章,有详细说明值得一提的是有掩码的话接

通信时发送的数据都是真实数据与掩码按按异或处理过的.

其他类其实都是一些基础部件, 详情查看源码.

ValueServer: 该类其实就是用套接口编写了一个服务端实现Accept,Receive,Send等相关事件

至于Socket服务端的具体实现请查看这位大牛的文章,有详细说明http://www.cnblogs.com/tianzhiliang/archive/2010/09/08/1821623.html

这里就不赘述了

客户端的实现就比较简单了 只要调用WebSocket的API就行了

具体如下:

WebSocket.js

   
    <script type="text/javascript">
        var noSupportMessage = "您的浏览器不支持WebSocket!";
        var ws;        function connectSocketServer() {            var messageBoard = $("#messageBoard");            var support = "MozWebSocket" in window ? 'MozWebSocket' : ('WebSocket' in window ? 'WebSocket' : null);            if (support == null) {                alert(noSupportMessage);
                messageBoard.append('*' + noSupportMessage + "<br />");
                return;
            }            messageBoard.append("* Connecting to server..<br />");
            try {                ws = new WebSocket('ws://localhost:3000');
            } catch (e) {                alert(e.Message);
            }            ws.onmessage = function (event) {                messageBoard.append(event.data + "<br />");
            }            ws.onopen = function () {                messageBoard.append('* Connection open<br />');
            }            ws.onclose = function () {                messageBoard.append('* Connection closed<br />');
            }
        }        function sendMessage() {            if (ws) {                var mssageBox = document.getElementById("messageBox");
                var user = document.getElementById("users");
                var msg = user.value + "<separator>" + mssageBox.value;
                ws.send(msg);
                mssageBox.value = "";
            } else {                alert(noSupportMessage);
            }
        }        window.onload = function () {            connectSocketServer();
        }
    </script>转自:http://blog.163.com/da7_1@126/blog/static/10407267820121016103055506/

用C# ASP.NET MVC 实现WebSocket相关推荐

  1. 在 Asp.NET MVC 中使用 SignalR 实现推送功能

    一,简介 Signal 是微软支持的一个运行在 Dot NET 平台上的 html websocket 框架.它出现的主要目的是实现服务器主动推送(Push)消息到客户端页面,这样客户端就不必重新发送 ...

  2. ASP.NET MVC随想录——漫谈OWIN

    什么是OWIN OWIN是Open Web Server Interface for .NET的首字母缩写,他的定义如下: OWIN在.NET Web Servers与Web Application之 ...

  3. ASP.NET MVC SignalR(1):背景

    系列目录:ASP.NET MVC SignalR 关键词:HTTP.轮询.WebSocket.Server-Sent Events.长轮询.forever frame. 1. HTTP HTTP(Hy ...

  4. asp.net(mvc) 框架

    1.NFine mvc+ef 2.Grove orm架构 3.NHibernate orm 4.NBear 5.petshop 6.Membership 7.Brnshop 网上商城 8.cms快速开 ...

  5. 使用 WPF+ ASP.NET MVC 开发 在线客服系统 (一)

    近段时间利用业余时间开发了一套在线客服系统,期间遇到过大大小小不少问题,好在都一一解决,最终效果也还可以,打算写一个系列的文章把开发过程详细的记录下来. 希望能够和更多的开发人员互相交流学习,也希望有 ...

  6. asp.net mvc让api返回json格式

    第一种方法 API完整代码 using Newtonsoft.Json; using System; using System.Collections.Generic; using System.Li ...

  7. ASP.NET MVC 2示例Tailspin Travel

    Tailspin Travel 是一个旅游预订的应用程序示例,最新版本采用ASP.NET MVC 2技术构建,主要使用 DataAnnotations 验证, 客户端验证和ViewModels,还展示 ...

  8. Asp.net MVC中的ViewData与ViewBag

    在Asp.net MVC 3 web应用程序中,我们会用到ViewData与ViewBag,对比一下: ViewData ViewBag 它是Key/Value字典集合 它是dynamic类型对像 从 ...

  9. ASP.NET MVC Identity 兩個多個連接字符串問題解決一例

    按照ASP.NET MVC Identity建立了一個用戶權限管理模塊,由于還要加自己已有的數據庫,所以建立了一個實體模型,建立了之后,發現登錄不了: 一直顯示"Login in faile ...

最新文章

  1. 【ZooKeeper】配置文件详解
  2. mysql 去掉日期.0_简单介绍MySQL数据库中日期中包含零值的问题
  3. 在Ring3上实现文件碎甲(解锁)功能
  4. 科沃斯机器人双十一全渠道成交额超7亿 两大爆款单品携手破亿
  5. php docker开发环境,使用Docker的PHP开发环境
  6. 创建型模式:单例模式(懒汉+饿汉+双锁校验+内部类+枚举)
  7. 基于梅尔频谱的音频信号分类识别(Pytorch)
  8. Machine Learning List
  9. 3499元被吐槽太贵!A15加持:新iPhone SE正式发布 还有“苍蝇绿”iPhone 13
  10. 机器学习--聚类分析(划分方法,层次方法、密度方法)
  11. oracle主键重复异常捕获,Oracle异常处理异常处
  12. 操作系统期末总复习(题库)
  13. 跨境电商开发,源码无加密
  14. 录音转换成mp3格式
  15. 堆排序(Heapsort)-全网最详细
  16. python爬虫数据可视化豆瓣评分top250_Python数据可视化:豆瓣电影TOP250
  17. Ubuntu 16.04 常用软件安装
  18. JEB2插件教程之一JEB2AutoRenameByTypeInfo.py
  19. python项目对接钉钉SDK
  20. 有关于毕业论文提纲范文

热门文章

  1. 洛谷P1282 多米诺骨牌 题解
  2. Adobe Photoshop快捷键_艾孜尔江摘录
  3. 资源下载--使用Proxy SwitchyOmega+postman下载资源
  4. 在Windows Mobile手机上运行Android
  5. 实验八---理解进程调度时机跟踪分析进程调度与进程切换的过程
  6. java中的LinkedList(链表)与ArrayList(动态数组):(2)尝试简单实现LinkedList
  7. 山沟沟里的技术脱贫:阿里工程师助平武蜂农物联网养蜂
  8. 史上最全的PHP常用函数大全,不看看你就out了(还会不断更新哦!)
  9. 情感分析的一些专业术语
  10. golang中的gin框架学习