用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
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
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>

转载于:https://www.cnblogs.com/zxtceq/p/6277950.html

c# 实现WebSocket相关推荐

  1. mqtt+htttp+websocket

    一.介绍 1.参考网址1:WebSocket协议:5分钟从入门到精通 2.参考网址2:WebSocket 教程(阮一峰) 二.应用 1.参考网址1:从 HTTP 到 MQTT:一个移动后端案例概述 2 ...

  2. Java后端WebSocket的Tomcat实现

    转自: http://blog.chenzuhuang.com/archive/28.html http://www.cnblogs.com/xdp-gacl/p/5193279.html 一.Web ...

  3. Java Websocket实例【服务端与客户端实现全双工通讯】

    Java Websocket实例[服务端与客户端实现全双工通讯] 现很多网站为了实现即时通讯,所用的技术都是轮询(polling).轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP ...

  4. 物联网协议对比(HTTP、websocket、XMPP、COAP、MQTT和DDS协议)

    目录 1.HTTP和websocket 2.XMPP 3.COAP 4.MQTT协议 5.DDS 对于物联网,最重要的是在互联网中设备与设备的通讯,现在物联网在internet通信中比较常见的通讯协议 ...

  5. node.js创建WebSocket服务,并使用原生js ES6完成对WebSocket数据交互

    注意,前情提示: 本代码基于<Node.js(nodejs)对本地JSON文件进行增.删.改.查操作(轻车熟路)> 传送门Node.js(nodejs)对本地JSON文件进行增.删.改.查 ...

  6. 使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容

    使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容 原文:使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容 版 ...

  7. 使用Node.js快速搭建WebSocket server

    原文地址:http://my.oschina.net/yushulx/blog/309413 目录[-] 安装 服务端 客户端 参考 安装 ? 1 npm install ws 服务端 server. ...

  8. python java web_Python 与 Java 使用 websocket 通信

    WebSocket协议是基于TCP的一种新的网络协议.它实现了浏览器与服务器全双工(full-duplex)通信--允许服务器主动发送信息给客户端. Java服务端 import java.io.IO ...

  9. Java项目:在线淘房系统(租房、购房)(java+SpringBoot+Redis+MySQL+Vue+SpringSecurity+JWT+ElasticSearch+WebSocket)

    源码获取:博客首页 "资源" 里下载! 该系统有三个角色,分别是:普通用户.房屋中介.管理员.普通用户的功能:浏览房屋信息.预约看房.和中介聊天.申请成为中介等等.房屋中介的功能: ...

  10. websocket心跳链接代码_WebSocket原理与实践(五)--心跳及重连机制

    在使用websocket的过程中,有时候会遇到网络断开的情况,但是在网络断开的时候服务器端并没有触发onclose的事件.这样会有:服务器会继续向客户端发送多余的链接,并且这些数据还会丢失.所以就需要 ...

最新文章

  1. Python全局解释器锁GIL与多线程
  2. vscode pylint 错误_VScode中报Unable to import #x27;xxx#x27; pylint的解决方案
  3. 使用ffmpeg循环推流(循环读取视频文件)推送RTMP服务器的方法
  4. Java求n以内素数_求0到n之间素数个数的序列(Java)
  5. [自制简单操作系统] 4、计时器(线性表实现优化中断)
  6. win10 联想键盘快捷键关闭_这些Win10键盘快捷键你必须掌握,系统高手必备技能...
  7. [ES6] 细化ES6之 -- 迭代器与生成器
  8. tomcat 查看当前请求数_原生线程池这么强大,Tomcat 为何还需扩展线程池?
  9. 异常 try – finally 注意的地方
  10. 异步类随机多址接入分析
  11. IntelliJ IDEA设置TortoiseSVN插件(Cannot run program svn)
  12. 数据可视化—如何利用R,制作DashBoard
  13. U盘写保护修复(亲测可用)
  14. python实现xlsx批量转xls(或者xls批量转xlsx)
  15. python库包的安装方法_python包,库安装的6个方法
  16. python打开网页并实现点击
  17. 东方通TongWeb部署
  18. 华为OD机试 - 英文输入法单词联想(Python) | 机试题+算法思路+考点+代码解析 【2023】
  19. navicat 表合并查询_数据库两个表合并命令
  20. 在labview中实现jk触发器使用JK触发器实现时序逻辑电路

热门文章

  1. Hexo Next动态背景Canvas_nest
  2. 计算机科学与技术 美国 研究生 gpa3.5 托福100,历年录取数据告诉你:美国研究生申请TOEFL、GRE、GPA需要考多少分?...
  3. 分享151个ASP源码,总有一款适合您
  4. Linux部署redis以及部署完成后,远程工具连接不上问题
  5. SAP PCA利润中心会计案例教程前台操作
  6. Vue 的响应式原理中 Object.defineProperty 有什么缺陷?为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?...
  7. ZYNQ7000 FSBL加载启动代码详解
  8. 微信小程序:全新趣味测试
  9. Pintos project 1 实验报告(代码分享)
  10. WorldFirst靠谱吗?跨境收款工具万里汇WorldFirst介绍!