yanbin's Blog

shell 管道两端的程序,并不是左边的程序先启动

$ ps aux  | grep "demo"
这条命令中的 ps 先启动,会导致程序异常退出。
因为写一个没有读端的管道,引发 SIGPIPE 信号,SIGPIPE 信号默认行为是终止程序的执行。
管道的创建者(shell) 先创建管道,启动 read 管道的程序 (grep), 再启动 write 管道的程序(ps aux).
读一个没有写端的管道会阻塞,grep 可以接受阻塞。
 
$ ps aux | grep "demo" | grep -v "grep"
这样的命令相当于: (ps aux | grep "demo") | grep -v "grep".

使用 libmosquitto 遇到的几个问题

1. 使用 libmosquitto 时必须要调用 mosquitto_loop_forever() 或者 mosquitto_loop();
 
2. mosquitto_loop_forever(); mosquitto_loop() 的第三个参数 max_packets 目前并没有使用,
    但是为了保持兼容性,必须设置为 1.
 
3. mosquitto_loop_start() 并不是在 thread 中调用,而是会启动一个 thread 处理 network  traffic, 
    称为 network thread; 同样的 mosquitto_loop_stop() 不是一定要在 thread 中调用,
    而是结束之前通过 mosquitto_loop_start() 创建的 network thread,
    mosquitto_loop_stop() 会等待 network thread 结束,而为了让 network thread 结束,
    又必须提前调用 mosquitto_disconnect(),
    不过可以通过设置 mosquitto_loop_stop() 的第二参数来强制 network thread 结束;

 
4.  注册 will message 同时指定 will topic。mosquitto_will_set() 的第二个参数就是指定 will topic 的。
     这就是 mqtt 里所说的 will message 有相应的 topic,  mosquitto_sub, mosquitto_pub 都有参数,
     可以指定 will topic: --will-topic;
 
5. 如果不使用 mosquitto_loop() 或者 mosquitto_loop_forever() 可以使用:
    (a) mosquitto_socket() 获取 connect socket handle;
    (b) 使用 select() 查询 socket handle 可读/可写;
    (c) 如果 select() 返回可读,mosquitto_read() 用来读取 message;
    (d) 如果返回可写,mosquitto_write() 用来发送 message;
    (e) 如果超时 mosquitto_loop_misc() 用来执行一些杂项;
 
6. libmosquitto 中 mosquitto_user_data_set() 可以设置 userdata,
    也可以在 mosquitto_new() 初始化时指定 userdata; 
    但是并没有接口获得 userdata; 毕竟 uesrdata 是外部数据,user 自己维护 userdata,
    当然应该知道指定给 mosquitto object 的 userdata 是哪一个。
 
7.保证 libmosquitto 和/或 mosquitto 版本一致。
   mosquitto-1.3.x 与 mosquitto-1.4 有兼容性问题。
   客户端使用中级 CA 签发的证书与 broker 建立 ssl 连接时,会有 tlsv1 alert unknown ca error.

 

mqtt 基础

0. mqtt 是一种轻量级的 publish/subscribe 消息传输协议。
   这是一个应用层协议, 一种互联网通信协议,并不依赖底层网络协议。
   正因为其轻量级,所以在低电量设备的中广泛应用。mqtt 可以应用在更多的情景。
   常见的应用:facebook, 微博。
 
1. mqtt message 规格:
   MAX LENGTH: The Payload length valid values are between 0 and 268,435,455 (0xf,fff,fff).
   没错是 7 个f, 256 * 1024 * 1024 - 1.
 
2. mqtt 之 "pub/sub":
   mqtt 的基础原理是推送消息(publishing messages)和订阅主题(subscribing topics), 称为 "pub/sub".
   clients 连接到 broker ---> subscrib topics, 其他 clients 连接到 broker ---> publish message 到 topic,
   所有订阅了这个 topic 并且在线的 clients 都会收到这条 message.
 
   假如 clients publish message 到 topic, 但是订阅这个 topic 的 clients
   都没有在线, 或者还没有 client 订阅这个 topic. 这条 message 将会被消失(被丢弃了?是的被丢弃了)。
   可以设置 message 的 retained flag,再有其他 client 订阅到 topic 时会收到这条 message.
 
   1) 如果 publish message 时有 client 订阅到 topic, 这个条 message 还会保留吗?
   2) FIXME: 保留的 message 发送过之后还会再次发送到其他后来订阅到 topic 的 client 吗?
      **** retained message 保证每当 client 订阅 topic 时,会把 message 发送到 client.
            所有新在线的 client 都可以收到这条 message 直到 borker 进程重启。
      **** 即使 broker 进程重启,也有办法从硬盘存储中读取之前的消息,并且按照消息类型安排发送。
 
3. mqtt, broker:
   提供通用的简单的接口,接受其他 client 的连接。client 可以将 subscribedmessage 存入 database、
   发送到 twitter. 当然也可以从 database, twitter 读取 message 并推送。
   协议接口是简单通用的,任何实现的 client 都可以连接到任何实现的 broker.
 
4. mqtt, topic:
   1) Messages in MQTT are published on topics. There is no need to configure a topic,
      publishing on it is enough.
      topic 不需要配置,也不需要预先创建,有 client publish message 或这 subscribed topic 时由 broker 创建。
 
   2) topic 是层级结构,使用 '/' 作为分隔符, 就像是 Linux/Unix 的文件系统路径结构一样。
 
   3) 支持两个通配符(wildcard): '+' 和 '#'.
      '+': 通配层级结构中的一层。 a/b/+/d, a/b/c1/d   a/b/c2/d   a/b/c3/d 都会匹配。
      '#': 通配层级结构中所有剩余的层。 a/#, a/b/c1/d   a/b/c2/d   a/b/c3/d
 
   5) Zero length topic levels:
      Zero length topic levels are valid.
      0 长度 topic levels 表现出非现实的行为。可能会表现出 '+' 的行为,也可能表现出 '#' 的行为。
      具体行为要看 topic 的层级结构。
      例如有如下层级结构:
      a/b/c/d
      a/b/c1/d
      a/b/x/d
 
      a/b//d 相当于 a/b/+/d/
      a/b/c/ 相当于 a/b/c/+
      a/b/   相当于 a/b/#
 
      1) 如果给出的 0 length topic level 不是最后一层,那么就相当于 '+';
      2) 如果给出的 0 length topic level 是最后一层,要看实际 topic
         层级结构中, 这一层是不是最后一层,(a)如果是最后一层,那么就相当于 '+';
         (b) 如果不是最后一层,就相当于 '#'; 
 
5. Quality of Service.
   QoS 有三个级别:0,  1,   2
   mqtt QoS 并不是 TCP/IP 网络中报文的 QoS. 也不是 Linux 网络管理中的 QoS.
   mqtt QoS 定义了消息的发送和接收方式:
 
   1) Higher levels of QoS are more reliable, but involve higher latency and have
      higher bandwidth requirements.
      越高级别的 QoS 越可靠。相应的高级别的 QoS 带宽消耗大,延迟高
      因为要做握手或者发送接收确认。
 
   2) 三种级别的 QoS 消息发送/接收方式:
      0: The broker/client will deliver the message once, with no confirmation.
         提交 message 一次,不执行‘确认’操作。
 
      1: The broker/client will deliver the message at least once, with
         confirmation required.
         提交 message 至少一次,含有‘确认’请求,会执行'确认'操作。
 
      2: The broker/client will deliver the message exactly once by using a
         four step handshake.
         使用'4步握手'保证精确的提交一次 message.
   
   3)  Messages may be sent at any QoS level, and clients may attempt to
       subscribe to topics at any QoS level
 
       当 publish message 使用的 QoS 不同于 subscribe message 使用的 QoS 时,
       message 发送到 subscribed client 时,使用较低级别的 QoS.
       e.g.:
       (a) published message 使用 QoS 2, 一个 client0 订阅时使用 QoS 0, 那么
           message 提交给这个 client0 时使用 QoS 0.
       (b) 另一个 client1 订阅到这个 Topic 使用 QoS 2, 那么 message 提交给这个
           client 时使用 QoS 2.
       (c) 如果一个 client2 订阅时使用 QoS 2, 另一个 client3 publish message 
           使用 QoS 0, message 提交给 client2 时使用 QoS 0.
 
6. Retained Messages.
   1) 所有的 message 都可以设置为保留的。broker 保留 message 直到所有的订阅者接收 message.
   2) 而且当一个新的 client 订阅这个 topic,这个条 message 也会提交到这个 client.
   3) 可以用 retained message 来实现"last known good"机制。
 
 
7. Clean session / Durable connections
   1) client 连接到 broker 时设置 clean session flag 为 false, client 与 broker
      间建立了一个长连接(Durable connnecton); 当 client 断开与 broker 的连接时,
      任何 subscriptions 还有剩余的 QoS 为 1 或 2 的 messages,
      那么会保存这些 subscriptions/messages 直到再次连接。
 
   2) 如果 clean session flag 为 true,就相当于 'session start', 当 disconnect 时,
      会移除这个 client 所有的 subscriptions.
 
8. wills.
   will 是一种 message, 无异于其他 mqtt message。
   在 client 与 broker 建立连接时,client 告知 broker 一个 will message,用来
   在 client 与 broker 不正常断开连接时发送 will message 到一个特殊的 topic。
   这个特殊的 topic 是一个 system topic; system topic 有特殊命名,有特殊的访问权限,用于管理。
   will message 同样可以设置 QoS.
 

libcurl 简单使用

1. 必须首先调用 curl_global_init(), 并且指定 CURL_GLOBAL_ALL 作为参数。

    curl_global_init() 会分配一些内存,用于内部的实现。

 

2. 调用 curl_global_cleanup() 清除 curl_global_init() 分配的资源。
    当然这个函数可以在程序任何执行之中调用,不一定是程序将要结束之前调用。
    在完成了所有与 liburl 有关的工作之后,调用 curl_global_cleanup().
 
3. 使用 easy-functions  或者 multi-functions
    1) easy-functions 一般来说可以满足基本工作。
    2) 调用 CURL *curl_easy_init() 获得一个 easy session handle, 其实可以说是获得一个 curl handle.
    3) 使用 curl_easy_setopt(); 指定一个要请求的 URL.
    4) 使用 curl_easy_perform(); 完成请求,这里可能会阻塞。
    5) 使用 curl_easy_cleanup(curl), 完成清理工作。
 
4) curl_global_init() 一般会从系统分配内存。
    也可以使用 curl_global_init_mem() 指定一个自定义的内存地址给 libcurl  用来分配内存 ,这个地址可以是 stack, 也可以是动态分配的。
 
5) 小例子。
#include <curl/curl.h>
#include <stdio.h>
#include <stdlib.h>
#define REMOTE_URL   "http://www.google.com"
int main(int argc, char **argv)
{
     CURL *curl; 
     CURLcode res;
     curl_global_init(CURL_GLOBAL_ALL);
     curl = curl_easy_init();
     if (curl) {
        curl_easy_setopt(curl, CURLOPT_URL, REMOTE_URL);
        curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
        res = curl_easy_perform(curl);
        if (res != CURLE_OK) 
           fprintf(stderr, "curl_easy_perform error: %s\n", curl_easy_strerror(res));
        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
    return 0;
}

 




Host by is-Programmer.com | Power by Chito 1.3.3 beta | © 2007 LinuxGem | Design by Matthew "Agent Spork" McGee