c#版 mqtt 3.1.1 client 实现
c# 版
mqtt 3.1.1 client
http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/mqtt-v3.1.1.html
上面为 3.1.1 协议报文
一个外链:
MQTT 3.1.1,值得升级的6个新特性
http://www.blogjava.net/yongboy/archive/2014/12/16/421460.html
socket 客服端,这里我用了 SocketAsyncEventArgs 来实现,
这里感觉要优化的地方还是挺多的,,希望大神指出不足之处
核心实现:
MqttConnection
using System;
using System.IO;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Diagnostics;
using nMqtt.Messages; namespace nMqtt
{
internal sealed class MqttConnection
{
Socket socket;
int m_nConnection = ;
public Action<byte[]> Recv; /// <summary>
/// Socket异步对象池
/// </summary>
SocketAsyncEventArgsPool socketAsynPool; public MqttConnection()
{
const int receiveBufferSize = ;
socketAsynPool = new SocketAsyncEventArgsPool(m_nConnection);
var bufferManager = new BufferManager(receiveBufferSize * m_nConnection, receiveBufferSize);
bufferManager.InitBuffer(); //按照连接数建立读写对象
for (int i = ; i < m_nConnection; i++)
{
var args = new SocketAsyncEventArgs();
args.Completed += IO_Completed;
args.UserToken = new RecvToken();
bufferManager.SetBuffer(args);
socketAsynPool.Push(args);
}
} public void Connect(string server, int port = )
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(server, port);
socket.ReceiveAsync(socketAsynPool.Pop());
} void IO_Completed(object sender, SocketAsyncEventArgs e)
{
switch (e.LastOperation)
{
case SocketAsyncOperation.Receive:
ProcessRecv(e);
break;
default:
throw new ArgumentException("nError in I/O Completed");
}
} void ProcessRecv(SocketAsyncEventArgs e)
{
Debug.WriteLine("----------------------- ProcessRecv:{0}", e.BytesTransferred);
var token = e.UserToken as RecvToken;
if (e.SocketError == SocketError.Success && e.BytesTransferred > )
{
var buffer = new byte[e.BytesTransferred];
Buffer.BlockCopy(e.Buffer, e.Offset, buffer, , buffer.Length); token.Message.AddRange(buffer); if (token.IsReadComplete)
{
if (Recv != null)
Recv(token.Message.ToArray());
token.Reset();
} socket.ReceiveAsync(e);
}
else
{
token.Reset();
//socketAsynPool.Push(e);
//socket.ReceiveAsync(e);
}
} public void SendMessage(MqttMessage message)
{
Debug.WriteLine("onSend:{0}", message.FixedHeader.MessageType);
using (var stream = new MemoryStream())
{
message.Encode(stream);
stream.Seek(, SeekOrigin.Begin);
Send(stream.ToArray());
}
} void Send(byte[] message)
{
try
{
socket.Send(message, SocketFlags.None);
}
catch (Exception ex)
{
Debug.WriteLine(ex);
}
} class RecvToken
{
/// <summary>
/// The read buffer size from the network
/// </summary>
public const int BufferSize = ; /// <summary>
/// The total bytes expected to be read from from the header of content
/// </summary>
public int Count
{
get
{
if (Message != null && Message.Count >= )
{
int offset = ;
byte encodedByte;
var multiplier = ;
var remainingLength = ;
do
{
encodedByte = Message[offset];
remainingLength += encodedByte & 0x7f * multiplier;
multiplier *= 0x80;
} while ((++offset <=) && (encodedByte & 0x80) != ); return remainingLength + offset;
}
return ;
}
} /// <summary>
/// The bytes associated with the message being read.
/// </summary>
public List<byte> Message { get; set; } = new List<byte>(); /// <summary>
/// The buffer the last stream read wrote into.
/// </summary>
public byte[] Buffer; /// <summary>
/// A boolean that indicates whether the message read is complete
/// </summary>
public bool IsReadComplete
{
get { return Message.Count >= Count; }
} public void Reset()
{
Buffer = new byte[BufferSize];
Message.Clear();
}
}
} public enum ConnectionState
{
/// <summary>
/// The MQTT Connection is in the process of disconnecting from the broker.
/// </summary>
Disconnecting, /// <summary>
/// The MQTT Connection is not currently connected to any broker.
/// </summary>
Disconnected, /// <summary>
/// The MQTT Connection is in the process of connecting to the broker.
/// </summary>
Connecting, /// <summary>
/// The MQTT Connection is currently connected to the broker.
/// </summary>
Connected, /// <summary>
/// The MQTT Connection is faulted and no longer communicating with the broker.
/// </summary>
Faulted
} internal sealed class SocketAsyncEventArgsPool
{
private readonly Stack<SocketAsyncEventArgs> pool; internal SocketAsyncEventArgsPool(int capacity)
{
pool = new Stack<SocketAsyncEventArgs>(capacity);
} internal void Push(SocketAsyncEventArgs item)
{
if (item == null)
throw new ArgumentNullException(nameof(item));
lock (pool)
{
pool.Push(item);
}
} internal SocketAsyncEventArgs Pop()
{
lock (pool)
return pool.Pop();
} internal int Count { get { return pool.Count; } }
} internal sealed class BufferManager
{
readonly int m_numBytes;
byte[] m_buffer;
readonly Stack<int> m_freeIndexPool;
int m_currentIndex;
readonly int m_bufferSize; public BufferManager(int totalBytes, int bufferSize)
{
m_numBytes = totalBytes;
m_currentIndex = ;
m_bufferSize = bufferSize;
m_freeIndexPool = new Stack<int>();
} /// <summary>
/// Allocates buffer space used by the buffer pool
/// </summary>
public void InitBuffer()
{
// create one big large buffer and divide that out to each SocketAsyncEventArg object
m_buffer = new byte[m_numBytes];
} /// <summary>
/// Assigns a buffer from the buffer pool to the specified SocketAsyncEventArgs object
/// </summary>
/// <returns>true if the buffer was successfully set, else false</returns>
public bool SetBuffer(SocketAsyncEventArgs args)
{
if (m_freeIndexPool.Count > )
{
args.SetBuffer(m_buffer, m_freeIndexPool.Pop(), m_bufferSize);
}
else
{
if ((m_numBytes - m_bufferSize) < m_currentIndex)
return false;
args.SetBuffer(m_buffer, m_currentIndex, m_bufferSize);
m_currentIndex += m_bufferSize;
}
return true;
} /// <summary>
/// Removes the buffer from a SocketAsyncEventArg object. This frees the buffer back to the
/// buffer pool
/// </summary>
public void FreeBuffer(SocketAsyncEventArgs args)
{
m_freeIndexPool.Push(args.Offset);
args.SetBuffer(null, , );
}
}
}
其中 RecvToken
public int Count
{
get
{
if (Message != null && Message.Count >= )
{
int offset = ;
byte encodedByte;
var multiplier = ;
var remainingLength = ;
do
{
encodedByte = Message[offset];
remainingLength += encodedByte & 0x7f * multiplier;
multiplier *= 0x80;
} while ((++offset <=) && (encodedByte & 0x80) != ); return remainingLength + offset;
}
return ;
}
}
此为报文长度,这里需多注意
例示:
using System;
using System.Text;
using nMqtt.Messages; namespace nMqtt.Test
{
class Program
{
static void Main(string[] args)
{
var client = new MqttClient("server", "clientId");
var state = client.Connect("username");
if (state == ConnectionState.Connected)
{
client.MessageReceived += OnMessageReceived;
client.Subscribe("a/b", Qos.AtLeastOnce);
}
Console.ReadKey();
} static void OnMessageReceived(string topic, byte[] data)
{
Console.WriteLine("-------------------");
Console.WriteLine("topic:{0}", topic);
Console.WriteLine("data:{0}", Encoding.UTF8.GetString(data));
}
}
}
最后:
代码托管至 https://github.com/dtxlink/nMqtt
c#版 mqtt 3.1.1 client 实现的更多相关文章
- 16-网页,网站,微信公众号基础入门(网页版MQTT,页面控件位置调整入门)
https://www.cnblogs.com/yangfengwu/p/11200767.html 说一下,只要你java学的很好,那么几乎所有的语言都不在话下了 来看一下样式设置 运行 在左上角感 ...
- 14-网页,网站,微信公众号基础入门(网页版MQTT,小试牛刀)
https://www.cnblogs.com/yangfengwu/p/11192639.html 抱歉哈...最近由于做板子,,教程的进度落下了... 这些天总共做了还几块板子 首先对当前这个教程 ...
- DotNetty 版 mqtt 开源客户端 (MqttFx)
一.DotNetty背景介绍 某天发现 dotnet 是个好东西,就找了个项目来练练手.于是有了本文的 Mqtt 客户端 (github: MqttFx ) DotNetty是微软的Azure ...
- 15-网页,网站,微信公众号基础入门(网页版MQTT,做自己的MQTT调试助手)
https://www.cnblogs.com/yangfengwu/p/11198572.html 说一下哈,,如果教程哪里看不明白...就去自己百度补充哪一部分,,学习不是死记硬背,需要会学习,永 ...
- C#版 Winform界面 Socket编程 Client客户端
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...
- mqtt client python example
This is a simple example showing how to use the [Paho MQTT Python client](https://eclipse.org/paho/c ...
- MQTT 协议学习:000-有关概念入门
背景 从本章开始,在没有特殊说明的情况下,文章中的MQTT版本均为 3.1.1. MQTT 协议是物联网中常见的协议之一,"轻量级物联网消息推送协议",MQTT同HTTP属于第七层 ...
- MQTT 协议是个啥?这篇文章告诉你!
文章首发于我的公众号「程序员cxuan」,欢迎大家关注呀- 说到做到! 之前有位读者给我留言说想要了解一下什么是 MQTT 协议,顺便还把我夸了一把,有点不好意思啦. 那么读者的要求必须要满足啊,所以 ...
- Oracle 精简绿色版客户端的配置
在项目开发中常常用到Oracle.但Oracle 客户端体积很大.安装后,主要用的就1个功能:TNS配置服务名,偶尔用到SqlPlus.在开发过程中,大量使用Navicate和PL/SQL Devel ...
随机推荐
- Linux(Unix)密码策略问题导致root密码不能修改
Linux(Unix)密码策略问题导致root密码不能修改 发布时间: 2016-01-19 浏览次数: 1034 下载次数: 5 用户修改了密码配置文件,导致root账户修改密码时报如下错误: ...
- nodejs 优雅的连接 mysql
1.mysql 及 promise-mysql nodejs 连接 mysql 有成熟的npm包 mysql ,如果需要promise,建议使用 promise-mysql: npm:https:// ...
- ICTPOS3.0 词性标注集
Ag 形语素 形容词性语素.形容词代码为a,语素代码g前面置以A. a 形容词 取英语形容词adjective的第1个字母. ad 副形词 直接作状语的形容词.形容词代码a和副词代码d并在一起. an ...
- 【bzoj4486】【JSOI2015】串分割
老省选题了. 首先考虑怎么比较超长数字的大小? 参见UTR1的那道题 先比size,然后比较字典序即可. 接下来考虑下切割的问题. 因为要将字符串切割成k份,所以这个字符串只会存在n/k个本质不同的起 ...
- 【模板】BZOJ 1692:队列变换—后缀数组 Suffix Array
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1692 题意: 给出一个长度为N的字符串,每次可以从串头或串尾取一个字符,添加到新串中,使新串 ...
- PBFT算法的相关问题
PBFT(99.02年发了两篇论文)-从开始的口头算法(指数级)到多项式级 要求 n>3f why: 个人简单理解:注意主节点是可以拜占庭的,从节点对于(n,v,m)的投票最开始也是基于主节点给 ...
- python--tesseract
tesseract的介绍 我们爬虫会受到阻碍,其中一个便是我们在模拟登陆或者请求一些数据的时候,出现的图形验证码,因此我们需要一种能叫图形验证码识别成文本的技术.将图片翻译成文字一般称为光学文字识别( ...
- django开发项目实例1--建立一个项目并初步运行
1:进入目标目录新建一个项目 D:\>django-admin.py startproject qiweijie 新建完成后,进入项目文件夹查看目录 D:\>cd qiweijie D:\ ...
- HDFS初识
参看原文 [Hadoop]HDFS的运行原理 参看原文 还不懂HDFS的工作原理?快来扫扫盲 简介 HDFS(Hadoop Distributed File System) Hadoop分布式文件系统 ...
- GT-----如何做Android应用流量测试?
1.如何判断一个应用的流量偏高? 如果看流量的绝对值看不出高低,那就找几个同类型的产品对比一下,如果完成同样的事物,被测应用比同类产品高很多,那就偏高了,可能有优化的空间. 2.如何找到有效的优化点? ...