c# 实现WebSocket
用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相关推荐
- mqtt+htttp+websocket
一.介绍 1.参考网址1:WebSocket协议:5分钟从入门到精通 2.参考网址2:WebSocket 教程(阮一峰) 二.应用 1.参考网址1:从 HTTP 到 MQTT:一个移动后端案例概述 2 ...
- Java后端WebSocket的Tomcat实现
转自: http://blog.chenzuhuang.com/archive/28.html http://www.cnblogs.com/xdp-gacl/p/5193279.html 一.Web ...
- Java Websocket实例【服务端与客户端实现全双工通讯】
Java Websocket实例[服务端与客户端实现全双工通讯] 现很多网站为了实现即时通讯,所用的技术都是轮询(polling).轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发 出HTTP ...
- 物联网协议对比(HTTP、websocket、XMPP、COAP、MQTT和DDS协议)
目录 1.HTTP和websocket 2.XMPP 3.COAP 4.MQTT协议 5.DDS 对于物联网,最重要的是在互联网中设备与设备的通讯,现在物联网在internet通信中比较常见的通讯协议 ...
- node.js创建WebSocket服务,并使用原生js ES6完成对WebSocket数据交互
注意,前情提示: 本代码基于<Node.js(nodejs)对本地JSON文件进行增.删.改.查操作(轻车熟路)> 传送门Node.js(nodejs)对本地JSON文件进行增.删.改.查 ...
- 使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容
使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容 原文:使用CEfSharp之旅(7)CEFSharp 拦截 http 请求 websocket 内容 版 ...
- 使用Node.js快速搭建WebSocket server
原文地址:http://my.oschina.net/yushulx/blog/309413 目录[-] 安装 服务端 客户端 参考 安装 ? 1 npm install ws 服务端 server. ...
- python java web_Python 与 Java 使用 websocket 通信
WebSocket协议是基于TCP的一种新的网络协议.它实现了浏览器与服务器全双工(full-duplex)通信--允许服务器主动发送信息给客户端. Java服务端 import java.io.IO ...
- Java项目:在线淘房系统(租房、购房)(java+SpringBoot+Redis+MySQL+Vue+SpringSecurity+JWT+ElasticSearch+WebSocket)
源码获取:博客首页 "资源" 里下载! 该系统有三个角色,分别是:普通用户.房屋中介.管理员.普通用户的功能:浏览房屋信息.预约看房.和中介聊天.申请成为中介等等.房屋中介的功能: ...
- websocket心跳链接代码_WebSocket原理与实践(五)--心跳及重连机制
在使用websocket的过程中,有时候会遇到网络断开的情况,但是在网络断开的时候服务器端并没有触发onclose的事件.这样会有:服务器会继续向客户端发送多余的链接,并且这些数据还会丢失.所以就需要 ...
最新文章
- Python全局解释器锁GIL与多线程
- vscode pylint 错误_VScode中报Unable to import #x27;xxx#x27; pylint的解决方案
- 使用ffmpeg循环推流(循环读取视频文件)推送RTMP服务器的方法
- Java求n以内素数_求0到n之间素数个数的序列(Java)
- [自制简单操作系统] 4、计时器(线性表实现优化中断)
- win10 联想键盘快捷键关闭_这些Win10键盘快捷键你必须掌握,系统高手必备技能...
- [ES6] 细化ES6之 -- 迭代器与生成器
- tomcat 查看当前请求数_原生线程池这么强大,Tomcat 为何还需扩展线程池?
- 异常 try – finally 注意的地方
- 异步类随机多址接入分析
- IntelliJ IDEA设置TortoiseSVN插件(Cannot run program svn)
- 数据可视化—如何利用R,制作DashBoard
- U盘写保护修复(亲测可用)
- python实现xlsx批量转xls(或者xls批量转xlsx)
- python库包的安装方法_python包,库安装的6个方法
- python打开网页并实现点击
- 东方通TongWeb部署
- 华为OD机试 - 英文输入法单词联想(Python) | 机试题+算法思路+考点+代码解析 【2023】
- navicat 表合并查询_数据库两个表合并命令
- 在labview中实现jk触发器使用JK触发器实现时序逻辑电路
热门文章
- Hexo Next动态背景Canvas_nest
- 计算机科学与技术 美国 研究生 gpa3.5 托福100,历年录取数据告诉你:美国研究生申请TOEFL、GRE、GPA需要考多少分?...
- 分享151个ASP源码,总有一款适合您
- Linux部署redis以及部署完成后,远程工具连接不上问题
- SAP PCA利润中心会计案例教程前台操作
- Vue 的响应式原理中 Object.defineProperty 有什么缺陷?为什么在 Vue3.0 采用了 Proxy,抛弃了 Object.defineProperty?...
- ZYNQ7000 FSBL加载启动代码详解
- 微信小程序:全新趣味测试
- Pintos project 1 实验报告(代码分享)
- WorldFirst靠谱吗?跨境收款工具万里汇WorldFirst介绍!