最近学习MQTT协议,选择了当前比较流行的MQTT Broker “mosquitto”,但是在阅读代码过程中发现其网络底层库封装的相当差劲。

对于MQTT协议的变长头长度的读取上,基本上采取每次一个byte的方式进行读取判断,对于系统调用read的高代价来讲,真的是相当的浪费,也难怪其不能作为高并发的服务器进行处理。

当然mosquitto需要优化的地方还很多:

1. 使用poll而不是使用epoll (可能是处于跨平台考虑,如果linux下可以使用epoll替换),同时的就是刚才提到的 byte 读取网络数据

2. 订阅树的管理上,对于大量的请求断开或者重练效率比较低

3. 空闲空间管理机制优化和数据包发送方式的修改

4. 内存管理上malloc new 没有使用mem pool机制,在大并发情况下,内存管理容易出现问题

5. 锁遍地飞,如果采用reactor_

但是从另一个方面讲,mosquitto作为开源的实现,思路上还是比较清晰,为mqtt服务器开发提供了比较完备的参考,这也就是它的价值所在了。

#ifdef WITH_BROKER

int _mosquitto_packet_read(struct mosquitto_db *db, struct mosquitto *mosq)

#else

int _mosquitto_packet_read(struct mosquitto *mosq)

#endif

{

uint8_t byte;

ssize_t read_length;

int rc = 0;

if(!mosq) return MOSQ_ERR_INVAL;

if(mosq->sock == INVALID_SOCKET) return MOSQ_ERR_NO_CONN;

if(mosq->state == mosq_cs_connect_pending){

return MOSQ_ERR_SUCCESS;

}

/* This gets called if pselect() indicates that there is network data

* available - ie. at least one byte.  What we do depends on what data we

* already have.

* If we've not got a command, attempt to read one and save it. This should

* always work because it's only a single byte.

* Then try to read the remaining length. This may fail because it is may

* be more than one byte - will need to save data pending next read if it

* does fail.

* Then try to read the remaining payload, where 'payload' here means the

* combined variable header and actual payload. This is the most likely to

* fail due to longer length, so save current data and current position.

* After all data is read, send to _mosquitto_handle_packet() to deal with.

* Finally, free the memory and reset everything to starting conditions.

*/

if(!mosq->in_packet.command){

read_length = _mosquitto_net_read(mosq, &byte, 1);

if(read_length == 1){

mosq->in_packet.command = byte;

#ifdef WITH_BROKER

#  ifdef WITH_SYS_TREE

g_bytes_received++;

#  endif

/* Clients must send CONNECT as their first command. */

if(!(mosq->bridge) && mosq->state == mosq_cs_new && (byte&0xF0) != CONNECT) return MOSQ_ERR_PROTOCOL;

#endif

}else{

if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */

#ifdef WIN32

errno = WSAGetLastError();

#endif

if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){

return MOSQ_ERR_SUCCESS;

}else{

switch(errno){

case COMPAT_ECONNRESET:

return MOSQ_ERR_CONN_LOST;

default:

return MOSQ_ERR_ERRNO;

}

}

}

}

/* remaining_count is the number of bytes that the remaining_length

* parameter occupied in this incoming packet. We don't use it here as such

* (it is used when allocating an outgoing packet), but we must be able to

* determine whether all of the remaining_length parameter has been read.

* remaining_count has three states here:

*   0 means that we haven't read any remaining_length bytes

*   <0 means we have read some remaining_length bytes but haven't finished

*   >0 means we have finished reading the remaining_length bytes.

*/

if(mosq->in_packet.remaining_count <= 0){

do{

read_length = _mosquitto_net_read(mosq, &byte, 1);

if(read_length == 1){

mosq->in_packet.remaining_count--;

/* Max 4 bytes length for remaining length as defined by protocol.

* Anything more likely means a broken/malicious client.

*/

if(mosq->in_packet.remaining_count < -4) return MOSQ_ERR_PROTOCOL;

#if defined(WITH_BROKER) && defined(WITH_SYS_TREE)

g_bytes_received++;

#endif

mosq->in_packet.remaining_length += (byte & 127) * mosq->in_packet.remaining_mult;

mosq->in_packet.remaining_mult *= 128;

}else{

if(read_length == 0) return MOSQ_ERR_CONN_LOST; /* EOF */

#ifdef WIN32

errno = WSAGetLastError();

#endif

if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){

return MOSQ_ERR_SUCCESS;

}else{

switch(errno){

case COMPAT_ECONNRESET:

return MOSQ_ERR_CONN_LOST;

default:

return MOSQ_ERR_ERRNO;

}

}

}

}while((byte & 128) != 0);

/* We have finished reading remaining_length, so make remaining_count

* positive. */

mosq->in_packet.remaining_count *= -1;

if(mosq->in_packet.remaining_length > 0){

mosq->in_packet.payload = _mosquitto_malloc(mosq->in_packet.remaining_length*sizeof(uint8_t));

if(!mosq->in_packet.payload) return MOSQ_ERR_NOMEM;

mosq->in_packet.to_process = mosq->in_packet.remaining_length;

}

}

while(mosq->in_packet.to_process>0){

read_length = _mosquitto_net_read(mosq, &(mosq->in_packet.payload[mosq->in_packet.pos]), mosq->in_packet.to_process);

if(read_length > 0){

#if defined(WITH_BROKER) && defined(WITH_SYS_TREE)

g_bytes_received += read_length;

#endif

mosq->in_packet.to_process -= read_length;

mosq->in_packet.pos += read_length;

}else{

#ifdef WIN32

errno = WSAGetLastError();

#endif

if(errno == EAGAIN || errno == COMPAT_EWOULDBLOCK){

if(mosq->in_packet.to_process > 1000){

/* Update last_msg_in time if more than 1000 bytes left to

* receive. Helps when receiving large messages.

* This is an arbitrary limit, but with some consideration.

* If a client can't send 1000 bytes in a second it

* probably shouldn't be using a 1 second keep alive. */

pthread_mutex_lock(&mosq->msgtime_mutex);

mosq->last_msg_in = mosquitto_time();

pthread_mutex_unlock(&mosq->msgtime_mutex);

}

return MOSQ_ERR_SUCCESS;

}else{

switch(errno){

case COMPAT_ECONNRESET:

return MOSQ_ERR_CONN_LOST;

default:

return MOSQ_ERR_ERRNO;

}

}

}

}

/* All data for this packet is read. */

mosq->in_packet.pos = 0;

#ifdef WITH_BROKER

#  ifdef WITH_SYS_TREE

g_msgs_received++;

if(((mosq->in_packet.command)&0xF5) == PUBLISH){

g_pub_msgs_received++;

}

#  endif

rc = mqtt3_packet_handle(db, mosq);

#else

rc = _mosquitto_packet_handle(mosq);

#endif

/* Free data and reset values */

_mosquitto_packet_cleanup(&mosq->in_packet);

pthread_mutex_lock(&mosq->msgtime_mutex);

mosq->last_msg_in = mosquitto_time();

pthread_mutex_unlock(&mosq->msgtime_mutex);

return rc;

}

MQTT 开源代理mosquitto的网络层封装相当sucks的更多相关文章

  1. MQTT开源代理Mosquitto源码分析(访问控制篇)

    一.整体流程概览 从GitHub下载源码后,代理的源码在src中,同时还用到了lib库中的一些函数.对项目的工作流程有个大概理解是分析mosquitto的访问控制权限的基础,网络上已有很多中文博客在介 ...

  2. 【转载】MQTT学习笔记——MQTT协议体验 Mosquitto安装和使用

    http://blog.csdn.net/xukai871105/article/details/39252653 0 前言     MQTT是IBM开发的一个即时通讯协议.MQTT是面向M2M和物联 ...

  3. MQTT入门1 -- mosquitto 安装

    原文链接:https://www.cnblogs.com/NickQ/p/9247638.html MQTT入门1 -- mosquitto 安装 简介: MQTT(Message Queuing T ...

  4. MQTT教學(二):安裝MQTT伺服器Mosquitto,Windows系統篇

    http://swf.com.tw/?p=1005 「認識MQTT」文章提到,MQTT的訊息全都透過稱為代理人(broker)的伺服器交流.本文將說明頗受歡迎的開放原始碼MQTT伺服器Mosquitt ...

  5. 在阿里云服务器上(centos 8) 安装自己的MQTT服务器 (mosquitto)

    layout: post title: 在阿里云服务器上(centos 8) 安装自己的MQTT服务器 (mosquitto) subtitle: date: 2020-3-2 author: Dap ...

  6. DotNetty 版 mqtt 开源客户端 (MqttFx)

    一.DotNetty背景介绍 某天发现 dotnet  是个好东西,就找了个项目来练练手.于是有了本文的 Mqtt 客户端   (github:  MqttFx ) DotNetty是微软的Azure ...

  7. arm linux 移植 MQTT (paho、mosquitto)

    前言 我们在这里做2件事情: 1)编译 paho.mqtt.mosquitto 2个开源项目的c版本库(mosquitto库没有用上) 2)编译好 依赖 paho.mqtt的库编写例程 + mosqu ...

  8. JeeSite是基于多个优秀的开源项目,高度整合封装而成的高效,高性能,强安全性的 开源 Java EE快速开发平台

    JeeSite本身是以Spring Framework为核心容器,Spring MVC为模型视图控制器,MyBatis为数据访问层, Apache Shiro为权限授权层,Ehcahe对常用数据进行缓 ...

  9. 使用Swift的代理,闭包来封装一个公用协议减少垃圾代码

    iOS开发中,如果不进行适当的封装,使用协议或者继承类来进行开发,你就会遇到传说中的ViewController(以后简称VC) Hell的问题…… 比如说,我们先声网App中为了调用接口,做简单的判 ...

随机推荐

  1. Uva 11294 婚姻

    题目链接:https://vjudge.net/contest/166461#problem/C 题意: n对夫妻,有m对人吵过架,不能排在同一边,求新娘的一边的人: 分析: 每对夫妻,看成两个点,女 ...

  2. 【[AHOI2012]树屋阶梯】

    卡特兰数! 至于为什么是卡特兰数,就稍微说那么一两句吧 对于一个高度为\(i\)的阶梯,我们可以在左上角填一个高度为\(k\)的阶梯,右下角填一个高度为\(i-1-k\)的阶梯剩下的我们用一个大的长方 ...

  3. WIN7系统 64位出现 Net Framework 数据提供程序要求 Microsoft Data Access Components(MDAC).

    WIN7系统 64位出现  Net Framework 数据提供程序要求 Microsoft Data Access Components(MDAC).请安装 Microsoft Data Acces ...

  4. P1171 售货员的难题 暴力dp

    题面 著名的TSP问题,NPC问题 对于数据大的情况,我们可以使用一系列近似算法进行寻找解. 对于数据规模小的情况,我们可以直接暴力dp 一开始写了一个dfs,然后就被n=20的数据卡爆了 #incl ...

  5. sql server 自增长显式添加值

    如果想在自增列添加数据,会提示我们不能插入显式值 解决:

  6. unity3D引擎:2D游戏自动瞄准算法实现

    转:http://blog.csdn.net/naitu/article/details/39555373 在很多飞行射击类游戏里,都有敌人向玩家自动瞄准并开火的功能.在这里本人用unity3D引擎新 ...

  7. 关于ProjectServer调用PSI 报Error GeneralReadOnlyColumn (20005) - column TS_ACT_FINISH_DATE错的解决方案

    TimesheetDataSet Table Actuals Row: TS_LINE_UID='f4b970f8-fb03-44d1-9997-cd31da42cb09' TS_ACT_START_ ...

  8. node学习----Promise 初见

    今天在网上查看promise资料,发现promise有三种状态,pending,fullfilled,rejected.分别对应了初始化状态,成功状态及失败状态.为了理解写测试代码来实验:functi ...

  9. JavaWeb项目中各个文件夹的作用

    /WEB-INF/web.xml Web应用程序配置文件,描述了 servlet 和其他的应用组件配置及命名规则. /WEB-INF/classes/ 包含了站点所有用的 class 文件,包括 se ...

  10. 第13届景驰-埃森哲杯广东工业大学ACM程序设计大赛--I-填空题

    链接:https://www.nowcoder.com/acm/contest/90/I 来源:牛客网 1.题目描述 牛客网是是一个专注于程序员的学习和成长的专业平台,集笔面试系统.课程教育.社群交流 ...