Mosquitto是一款实现了 MQTT v3.1 协议的开源消息代理软件,提供轻量级的,支持发布/订阅的的消息推送模式,使设备对设备之间的短消息通信简单易用。
1.下载解压、安装Mosquitto:http://mosquitto.org/files/source/,我使用当前做新版本1.3.5
wget http://mosquitto.org/files/source/mosquitto-1.3.5.tar.gz
解压:tar -zxvf mosquitto-1.3.5.tar.gz
cd mosquitto-1.3.5
在编译前需要g++和openssl支持,若没有安装请使用如下命令安装:
yum -y install gcc gcc-c++
yum -y install openssl openssl-devel
yum update openssl
除此之外还需修改安装选项配置config.mk:
# 是否支持tcpd/libwrap功能.
#WITH_WRAP:=yes
# 是否开启SSL/TLS支持
#WITH_TLS:=yes
# 是否开启TLS/PSK支持
#WITH_TLS_PSK:=yes
# Comment out to disable client client threading support.
#WITH_THREADING:=yes
# 是否使用严格的协议版本(老版本兼容会有点问题)
#WITH_STRICT_PROTOCOL:=yes
# 是否开启桥接模式
#WITH_BRIDGE:=yes
# 是否开启持久化功能
#WITH_PERSISTENCE:=yes
# 是否监控运行状态
#WITH_MEMORY_TRACKING:=yes
这里需要注意的是,默认情况下Mosquitto的安装需要OpenSSL的支持;如果不需要SSL,则需要关闭config.mk里面的某些与SSL功能有关的选项(WITH_TLS、WITH_TLS_PSK)。
另外编译过程找不到ares.h,需要把srv support 关掉
WITH_SRV:=yes,改为WITH_SRV:=no
安装、编译
make
make install
完成后在命令行里发现mosquitto、mosquitto_pub和mosquitto_sub三个工具,分别用于启动代理、发布消息和订阅消息。
注:在使用过程中找不到libmosquitto.so.1
error while loading shared libraries: libmosquitto.so.1: cannot open shared object file: No such file or directory
解决方法:修改libmosquitto.so位置
# 创建链接
ln -s /usr/local/lib/libmosquitto.so.1 /usr/lib/libmosquitto.so.1
# 更新动态链接库
ldconfig
2.配置&运行
安装完成之后,所有配置文件会被放置于/etc/mosquitto/目录下,其中最重要的就是Mosquitto的配置文件,即mosquitto.conf,以下是详细的配置参数说明:
# =================================================================
# General configuration
# =================================================================
# 客户端心跳的间隔时间
#retry_interval 20
# 系统状态的刷新时间
#sys_interval 10
# 系统资源的回收时间,0表示尽快处理
#store_clean_interval 10
# 服务进程的PID
#pid_file /var/run/mosquitto.pid
# 服务进程的系统用户
#user mosquitto
# 客户端心跳消息的最大并发数
#max_inflight_messages 10
# 客户端心跳消息缓存队列
#max_queued_messages 100
# 用于设置客户端长连接的过期时间,默认永不过期
#persistent_client_expiration
# =================================================================
# Default listener
# =================================================================
# 服务绑定的IP地址
#bind_address
# 服务绑定的端口号
#port 1883
# 允许的最大连接数,-1表示没有限制
#max_connections -1
# cafile:CA证书文件
# capath:CA证书目录
# certfile:PEM证书文件
# keyfile:PEM密钥文件
#cafile
#capath
#certfile
#keyfile
# 必须提供证书以保证数据安全性
#require_certificate false
# 若require_certificate值为true,use_identity_as_username也必须为true
#use_identity_as_username false
# 启用PSK(Pre-shared-key)支持
#psk_hint
# SSL/TSL加密算法,可以使用“openssl ciphers”命令获取
# as the output of that command.
#ciphers
# =================================================================
# Persistence
# =================================================================
# 消息自动保存的间隔时间
#autosave_interval 1800
# 消息自动保存功能的开关
#autosave_on_changes false
# 持久化功能的开关
persistence true
# 持久化DB文件
#persistence_file mosquitto.db
# 持久化DB文件目录
#persistence_location /var/lib/mosquitto/
# =================================================================
# Logging
# =================================================================
# 4种日志模式:stdout、stderr、syslog、topic
# none 则表示不记日志,此配置可以提升些许性能
log_dest none
# 选择日志的级别(可设置多项)
#log_type error
#log_type warning
#log_type notice
#log_type information
# 是否记录客户端连接信息
#connection_messages true
# 是否记录日志时间
#log_timestamp true
# =================================================================
# Security
# =================================================================
# 客户端ID的前缀限制,可用于保证安全性
#clientid_prefixes
# 允许匿名用户
#allow_anonymous true
# 用户/密码文件,默认格式:username:password
#password_file
# PSK格式密码文件,默认格式:identity:key
#psk_file
# pattern write sensor/%u/data
# ACL权限配置,常用语法如下:
# 用户限制:user <username>
# 话题限制:topic [read|write] <topic>
# 正则限制:pattern write sensor/%u/data
#acl_file
# =================================================================
# Bridges
# =================================================================
# 允许服务之间使用“桥接”模式(可用于分布式部署)
#connection <name>
#address <host>[:<port>]
#topic <topic> [[[out | in | both] qos-level] local-prefix remote-prefix]
# 设置桥接的客户端ID
#clientid
# 桥接断开时,是否清除远程服务器中的消息
#cleansession false
# 是否发布桥接的状态信息
#notifications true
# 设置桥接模式下,消息将会发布到的话题地址
# $SYS/broker/connection/<clientid>/state
#notification_topic
# 设置桥接的keepalive数值
#keepalive_interval 60
# 桥接模式,目前有三种:automatic、lazy、once
#start_type automatic
# 桥接模式automatic的超时时间
#restart_timeout 30
# 桥接模式lazy的超时时间
#idle_timeout 60
# 桥接客户端的用户名
#username
# 桥接客户端的密码
#password
# bridge_cafile:桥接客户端的CA证书文件
# bridge_capath:桥接客户端的CA证书目录
# bridge_certfile:桥接客户端的PEM证书文件
# bridge_keyfile:桥接客户端的PEM密钥文件
#bridge_cafile
#bridge_capath
#bridge_certfile
#bridge_keyfile
# 自己的配置可以放到以下目录中
include_dir /etc/mosquitto/conf.d
启动服务:
mosquitto -c /etc/mosquitto/mosquitto.conf -d #-d background running
[root@localhost mosquitto]# mosquitto -c mosquitto.conf -d
[root@localhost mosquitto]# 1421739302: Warning: Mosquitto should not be run as root/administrator.
1421739302: mosquitto version 1.3.5 (build date 2015-01-19 22:06:46-0800) starting
1421739302: Config loaded from mosquitto.conf.
1421739302: Opening ipv4 listen socket on port 1883.
1421739302: Opening ipv6 listen socket on port 1883.
从启动日志可以看出,监听1883端口。
Mosquitto是个异步IO框架,经测试可以轻松处理20000个以上的客户端连接。当然,实际的最大承载量还和业务的复杂度还有比较大的关系。压力测试的时候不要忘记调整系统的最大连接数和栈大小,比如:Linux上可用ulimit -n20000 -s512命令设置你需要的系统参数。
3.测试
一个完整的MQTT示例包括一个代理器,一个发布者和一个订阅者。测试分为以下几个步骤:
【1】启动服务mosquitto。
【2】订阅者通过mosquitto_sub订阅指定主题的消息。
【3】发布者通过mosquitto_pub发布指定主题的消息。
【4】代理服务器把该主题的消息推送到订阅者。
为了实现这个简单的测试案例,需要在linux中打开三个控制台,分别代表代理服务器、发布者和订阅者。
(1)启动代理服务
mosquitto -v
【-v】打印更多的调试信息
(2)订阅主题
mosquitto_sub -v -t mqtt_test
【-t】指定主题,此处为sensor
【-v】打印更多的调试信息
(3)发布内容
mosquitto_pub -t mqtt_test -m "hello world "
【-t】指定主题
【-m】指定消息内容
(4)运行结果
代理broker服务:
[root@localhost mosquitto]# mosquitto -c mosquitto.conf -d
[root@localhost mosquitto]# 1421739302: Warning: Mosquitto should not be run as root/administrator.
1421739302: mosquitto version 1.3.5 (build date 2015-01-19 22:06:46-0800) starting
1421739302: Config loaded from mosquitto.conf.
1421739302: Opening ipv4 listen socket on port 1883.
1421739302: Opening ipv6 listen socket on port 1883.
1421739302: New connection from ::1 on port 1883.
1421739302: New client connected from ::1 as mosqsub/4726-localhost (c1, k60).
1421739306: New connection from ::1 on port 1883.
1421739306: New client connected from ::1 as mosqpub/4850-localhost (c1, k60).
订阅主题:
[root@localhost ~]# mosquitto_sub -v -t mqtt_test
mqtt_test hello world
mqtt_test hello world
发布内容:
[root@localhost ~]# mosquitto_pub -t mqtt_test -m "hello world "
mosquitto_pub 客户端可发布一条消息到指定主题:
用法:
mosquitto_pub [-d] [-h hostname] [-i client_id] [-I client id prefix] [-p port number] [-q message QoS] [--quiet] [-r] { -f file | -l | -m message | -n | -s} [-u username [-P password] ] [ --will-topic topic [--will-payload payload] [--will-qos qos] [--will-retain] ] -t message-topic
选项:
-d, --debug
开启debug选项
-f, --file
把一个文件的内容做为消息的内容发送。经测试,支持txt文件,不支持doc等其他形式文件。
-h, --host
说明所连接到的域名,默认是localhost
-i, --id
客户端的ID号,如果没有指定,默认是mosquitto_pub_加上客户端的进程id,不能和--id_prefix同时使用。
-I, --id-prefix
指定客户端ID的前缀,与客户端的进程ID连接组成客户端的ID,不能喝--id同时使用。
-l, --stdin-line
从总段读取输入发送消息,一行为一条消息,空白行不会被发送。
-m, --message
从命令行发送一条消息,-m后面跟发送的消息内容。
-n, --null-message
发送一条空消息。
-p, --port
连接的端口号,默认是1883.
-P, --pw
指定密码用于代理认证,使用此选项时必须有有效的用户名。
-q, --qos
指定消息的服务质量,可以为0,1,2,默认是0.
--quiet
如果指定该选项,则不会有任何错误被打印,当然,这排除了无效的用户输入所引起的错误消息。
-r, --retain
如果指定该选项,该条消息将被保留做为最后一条收到的消息。下一个订阅消息者将能至少收到该条消息。
-s, --stdin-file
从标准输入接收传输的消息内容,所有输入做为一条消息发送。
-t, --topic
指定消息所发布到哪个主题。
-u, --username
指定用户名用于代理认证。
--will-payload
如果指定该选项,则万一客户端意外和代理服务器断开,则该消息将被保留在服务端并发送出去,该选项必须同时用--will-topic指定主题。
--will-qos
指定Will的服务质量,默认是0.必须和选项 --will-topic同时使用.
--will-retain
如果指定该选项,则万一客户端意外断开,已被发送的消息将被当做retained消息。必须和选项 --will-topic同时使用.
--will-topic
指定客户端意外断开时,Will消息发送到的主题。
sub_client客户端订阅一个或多个主题的消息:
用法:
mosquitto_sub [-c] [-d] [-h hostname] [-i client_id] [-I client id prefix] [-k keepalive time] [-p port number] [-q message QoS] [--quiet] [-v] [ -u username [-Ppassword] ] [ --will-topic topic [--will-payload payload] [--will-qos qos] [--will-retain] ] -t message topic ...
命令:
mosquitto_sub 订阅到主题,接收到消息时打印
选项:
-c, --disable-clean-session
禁止'clean session'选项,即如果客户端断开连接,这个订阅仍然保留来接收随后到的QoS为1和2的消息,当改客户端重新连接之后,它将接收到已排在队列中的消息。建议使用此选项时,客户端id选项设为--id
If using this option, it is recommended that the client id is set manually with --id
-d, --debug
开启debug选项
-h, --host
说明所连接到的域名,默认是localhost
-i, --id
客户端的ID号,如果没有指定,默认是mosquitto_pub_加上客户端的进程id,不能和--id_prefix同时使用。
-I, --id-prefix
指定客户端ID的前缀,与客户端的进程ID连接组成客户端的ID,不能喝--id同时使用。
-k, --keepalive
给代理发送PING命令(目的在于告知代理该客户端连接保持且在正常工作)的间隔时间,默认是60s
-p, --port
说明客户端连接到的端口,默认是1883
-P, --pw
指定密码用于代理认证,使用此选项时必须有有效的用户名。
-q, --qos
指定消息的服务质量,可以为0,1,2,默认是0.
--quiet
如果指定该选项,则不会有任何错误被打印,当然,这排除了无效的用户输入所引起的错误消息。
-t, --topic
指定订阅的消息主题,允许同时订阅到多个主题
-u, --username
指定用户名用于代理认证。
-v, --verbose
冗长地打印收到的消息。若指定该选项,打印消息时前面会打印主题名——“主题 消息内容”,否则,只打印消息内容
--will-payload
如果指定该选项,则万一客户端意外和代理服务器断开,则该消息将被保留在服务端并发送出去,该选项必须同时用--will-topic指定主题。
--will-qos
指定Will的服务质量,默认是0.必须和选项 --will-topic同时使用.
--will-retain
如果指定该选项,则万一客户端意外断开,已被发送的消息将被当做retained消息。必须和选项 --will-topic同时使用.
--will-topic
指定客户端意外断开时,Will消息发送到的主题。
报文种类
1.连接请求(CONNECT)
当一个从客户端到服务器的TCP/IP套接字连接被建立时,必须用一个连接流来创建一个协议级别的会话。
2.连接请求确认(CONNECTACK)
连接请求确认报文(CONNECTACK)是服务器发给客户端,用以确认客户端的连接请求
3.发布报文(PUBLISH)
客户端发布报文到服务器端,用来提供给有着不同需求的订阅者们。每个发布的报文都有一个主题,这是一个分层的命名空间,他定义了报文来源分类,方便订阅者订阅他们需要的主题。订阅者们可以注册自己的需要的报文类别。
4.发布确认报文(PUBACK)
发布确认报文(PUBACK)是对服务质量级别为1的发布报文的应答。他可以是服务器对发布报文的客户端的报文确认,也可以是报文订阅者对发布报文的服务器的应答。
5.发布确认报文(PUBREC)
PUBREC报文是对服务质量级别为2的发布报文的应答。这是服务质量级别为2的协议流的第二个报文。PUBREC是由服务器端对发布报文的客户端的应答,或者是报文订阅者对发布报文的服务器的应答。
6.发布确认报文(PUBREL)
PUBREL是报文发布者对来自服务器的PUBREC报文的确认,或者是服务器对来自报文订阅者的PUBREC报文的确认。它是服务质量级别为2的协议流的第三个报文。
7.确定发布完成(PUBCOMP)
PUBCOMP报文是服务器对报文发布者的PUBREL报文的应答,或者是报文订阅者对服务器的PUBREL报文的应答。它是服务质量级别为2的协议流的第四个也是最后一个报文。
8.订阅命名的主题(SUBSCRIBE)
订阅报文(SUBSCRIBE)允许一个客户端在服务器上注册一个或多个感兴趣的主题名字。发布给这些主题的报文作为发布报文从服务器端交付给客户端。订阅报文也描述了订阅者想要收到的发布报文的服务质量等级。
9. 订阅报文确认(SUBACK)
当服务器收到客户端发来的订阅报文时,将发送订阅报文的确认报文给客户端。一个这样的确认报文包含一列被授予的服务质量等级。被授予的服务质量等级次序和对应的订阅报文中的主题名称的次序相符。
10. 退订命名的主题(UNSUBSCRIBE)
退订主题的报文是从客户端发往服务器端,用以退订命名的主题。
11. 退订确认(UNSUBACK)
退订确认报文是从服务器发往客户端,用以确认客户端发来的退订请求报文。
12. Ping请求(PINGREQ)
Ping请求报文是从连接的客户端发往服务器端,用来询问服务器端是否还存在。
13. Ping应答(PINGRESP)
Ping应答报文是从服务器端发往Ping请求的客户端,对客户端的Ping请求进行确认。
14. 断开通知(DISCONNECT)
断开通知报文是从客户端发往服务器端用来指明将要关闭它的TCP/IP连接,他允许彻底地断开,而非只是下线。如果客户端已经和干净会话标志集联系,那么所有先前关于客户端维护的信息将被丢弃。一个服务器在收到断开报文之后,不能依赖客户端关闭TCP/IP连接。