后台开发学习笔记(二十四、libzmq模型 下)

上一篇好像就只是说了发布订阅模型,这一篇要把剩下的讲完,不过应该可以讲完,加油。

24.1 管道模型

管道模式用于将数据分布到分布在管道中的节点。数据总是沿着管道向下流动,管道的每个阶段都连接到至少一个节点。当一个管道阶段连接到多个节点时,所有连接节点之间的数据是循环的。

24.1.1 ZMQ_PUSH/ZMQ_PULL

在这里插入图片描述
看着这个模型真的有点像推流,其实我到现在还不是很清楚推流,不过可以用这个模型推一个视频文件。

客户端代码:

#include <iostream>
#include <string.h>
#include "zmq.hpp"
#include <unistd.h>
#include <arpa/inet.h>
#include <stdio.h>

using namespace std;
// export LD_LIBRARY_PATH="&LD_LIBRARY_PATH:/usr/local/lib"
// g++ main.cpp -lzmq -o main
/**
    * @brief  Main构造函数
    * @param  
    * @retval 
    */ 
char file_buff[1024];
int file_one_read = 1024;

int main(int argc, char **argv)
{

    if(argc != 3) {
        return -1;
    }

    char *ip = argv[1];
    char *file = argv[2];
    printf("ip = %s %s\n", ip, file);
    zmq::context_t context (1);

    char buff[200];
    snprintf(buff, sizeof(buff), "tcp://%s", ip);
    zmq::socket_t socket(context, ZMQ_PUSH);
    socket.setsockopt(ZMQ_SNDTIMEO, 0);
    //socket.connect(buff);
    socket.connect("tcp://122.51.111.216:5555");

    sleep(1);

    zmq::message_t mess(128);
    long file_path_len = strlen(file);
    file_path_len = htonl(file_path_len);
    printf("file %d %s\n", file_path_len, file);
    socket.send(&file_path_len, 4, ZMQ_SNDMORE);
    socket.send(file, strlen(file), ZMQ_SNDMORE);
    //socket.send(mess, ZMQ_SNDMORE);

    FILE *fp = fopen(file, "rb");
    if(fp == NULL) {
        printf("file no exist\n");
        return -1;
    }

    int size = 0;
    int pos = size;
    int count = 0;
    while(1)
    {
        fseek(fp, pos, SEEK_SET);
        size = fread(file_buff, 1, sizeof(file_buff), fp);
        if(size < 0) {
            printf("read file fail\n");
            socket.send(file_buff, 0, 0);
            break;
        } else if(size == file_one_read) {
            socket.send(file_buff, size, ZMQ_SNDMORE);
            printf("send %d\n", count++);
        } else if(size < file_one_read) {
            socket.send(file_buff, size, 0);
            printf("send file succces %s\n", file_buff);
            break;
        }
        pos += size;
    }

    fclose(fp);

    socket.close();
    context.close();

    return 0;
}

服务器端代码:

int main(int argc, char **argv)
{
    zmq::context_t context (1);

    zmq::socket_t socket(context, ZMQ_PULL);
    socket.setsockopt(ZMQ_RCVTIMEO, 0);

    socket.bind("tcp://*:5555");

    zmq::pollitem_t items [] = {
        { socket, 0, ZMQ_POLLIN, 0 }
    };

    long file_path_len = 0;
    char file[128] = {0};
   // file_head_t head;

    while(1) 
    {
        int rc = zmq::poll (&items[0], 1, -1);

	    if (items[0].revents & ZMQ_POLLIN)
        {
            
            zmq::message_t mess;
            socket.recv(&mess);
            memcpy(&file_path_len, mess.data(), sizeof(file_path_len));
            printf("file %d\n", file_path_len);
            file_path_len = ntohl(file_path_len);

            socket.recv(&mess);
            memcpy(file, mess.data(), file_path_len);

            printf("接收到的数据 %d %d %s\n", mess.size(), file_path_len, file);

            FILE *fp = fopen(file, "wb+");
            if(fp == NULL) {
                printf("file no exist\n");
                //goto exit;
            }

            while(1) {
                //socket.recv(&mess);
                bool more = mess.more();
                printf("more %d\n", more);
                if(more) {          //还有内容
                    socket.recv(&mess);
                    printf("ss %s\n", mess.data());
                    fwrite(mess.data(), 1, mess.size(), fp);
                } else {        //没有其他内容了
                    break;
                }

            }
            fclose(fp);
            printf("recv file sussce\n");
        }
        
        items[0].revents = 0;
    }
    
exit:
    
    socket.close();
    context.close();

    return 0;
}

这个模型需要注意的是,我们使用的是发送多针包,需要发送一个结束帧之后,服务器才能接受到数据,当初就是不知道这个,一直在测试,怎么就接受不到数据。

24.2 独立对模型

独立对模式用来精确的连接另一个对端。这种模式通过inproc方式用来进程内部通信。

24.2.1 ZMQ_PAIR

ZMQ_PAIR类型的套接字在每一时刻只能链接到一个对端上。不会有消息被路由或者过滤的操作发生在发送给ZMQ_PAIR套接字的的消息上。

当ZMQ_PAIR类型的套接字由于连接的对端到达高水位而进入静默状态,或者没有可用的对端可以连接,在这个套戒指上的所有zmq_send(3)操作都会进入阻塞,直到本套接字可以发送消息为止;消息不会被丢弃。

这个进程通信,目前不细讲,以后用到的时候再讲讲。

24.3 本地模型

本机模式用于与TCP对等端通信,并允许异步请求和双向应答。

24.3.1 ZMQ_STREAM

使用tcp://传输时,类型为ZMQ_STREAM的套接字用于从非ØMQ对等方发送和接收TCP数据。 ZMQ_STREAM套接字可以充当客户端和/或服务器,异步发送和/或接收TCP数据。

当接收TCP数据时,在将消息传递给应用程序之前,ZMQ_STREAM套接字应在消息部分之前包含消息的始发对等方的路由ID。 接收到的消息在所有连接的同级之间公平排队。

发送TCP数据时,ZMQ_STREAM套接字应删除消息的第一部分,并使用它来确定消息应路由到的对等方的路由ID,并且不可路由的消息将导致EHOSTUNREACH或EAGAIN错误。

要打开与服务器的连接,请使用zmq_connect调用,然后使用带有ZMQ_ROUTING_ID选项的zmq_getsockopt调用获取套接字路由ID。

要关闭特定连接,请发送路由ID帧,后跟零长度消息(请参见示例部分)。

建立连接后,应用程序将收到零长度的消息。 同样,当对等方断开连接(或连接断开)时,应用程序将收到零长度消息。

您必须先发送一个路由ID帧,然后发送一个数据帧。 ZMQ_SNDMORE标志是路由ID帧所必需的,但在数据帧上将被忽略。

这个我是直接翻译复制过来,不知道这个zmq为什么会写这个的例子,可能是本机测试的把。

void *ctx = zmq_ctx_new ();
assert (ctx);
/* Create ZMQ_STREAM socket */
void *socket = zmq_socket (ctx, ZMQ_STREAM);
assert (socket);
int rc = zmq_bind (socket, "tcp://*:8080");
assert (rc == 0);
/* Data structure to hold the ZMQ_STREAM routing id */
uint8_t routing_id [256];
size_t routing_id_size = 256;
/* Data structure to hold the ZMQ_STREAM received data */
uint8_t raw [256];
size_t raw_size = 256;
while (1) {
 /* Get HTTP request; routing id frame and then request */
 routing_id_size = zmq_recv (socket, routing_id, 256, 0);
 assert (routing_id_size > 0);
 do {
 raw_size = zmq_recv (socket, raw, 256, 0);
 assert (raw_size >= 0);
 } while (raw_size == 256);
 /* Prepares the response */
 char http_response [] =
 "HTTP/1.0 200 OK\r\n"
 "Content-Type: text/plain\r\n"
 "\r\n"
 "Hello, World!";
 /* Sends the routing id frame followed by the response */
 zmq_send (socket, routing_id, routing_id_size, ZMQ_SNDMORE);
 zmq_send (socket, http_response, strlen (http_response), 0);
 /* Closes the connection by sending the routing id frame followed by a zero response */
 zmq_send (socket, routing_id, routing_id_size, ZMQ_SNDMORE);
 zmq_send (socket, 0, 0, 0);
}
zmq_close (socket); zmq_ctx_destroy (ctx);

24.4 Request-reply 模型

请求答复模型,这个模型比较重要,要好好讲讲。

24.4.1 ZMQ_REQ/ZMQ_REP

这个模式就是请求-回复模式,客户端发送一个请求,服务器就回复,这个在上节,已经讲过了,这里就不讲了。
在这里插入图片描述

24.4.2 ZMQ_ROUTER/ZMQ_DEALER

在这里插入图片描述
这一对套接字也是为了解决上面的REP/REQ的水平不扩展性,而想出来的办法,这个跟我讲的XPUB/XSUB差不多,也是需要代理也解决的,这里的代码就不写了,因为看着差不多。

zmq_socket(3),这个是socket的官方API。

补充内容:
在这里插入图片描述

24.5 zmq设置消息路由

在这里插入图片描述
有可能在实际的应用中,有几个消息是需要顺序执行的,是有依赖关系的,所以这个时候就需要把这几个有关系的消息,统一发送到一个结点上,如果随机发送到不同结点的话,可能执行的顺序就会乱,所以这个需要我们需要设置路由信息。但是这里比较懒,好像也没使用到这种地步,所以目前先不写,以后碰到了再回来看看。

24.6 zmq测试

官方给出了测试实现的代码:libzmq-master\perf
就在下载的源码包里,以后如果需要做测试的话,可以参考一下这个程序,这里留个笔记。

ZMQ的测试方法:
http://wiki.zeromq.org/whitepapers:measuring-performance

ZMQ的测试结果:
http://wiki.zeromq.org/area:results

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值