• ZeroMQ_02 提问-回答模式


    提问-应答

    让我们从简单的代码开始,一段传统的Hello World程序。我们会创建一个客户端和一个服务端,客户端发送Hello给服务端,服务端返回World。

    Server

    #include <stdio.h>
    #include <zmq.h>
    #include <string.h>
    #include <unistd.h>
    
    #define buffersize 4096
    
    int main(int argc, char* argv[])
    {
        // [0]创建对象
        void* ctx = zmq_ctx_new();
        void* server = zmq_socket(ctx, ZMQ_REP);
        // [1]绑定到7766端口
        zmq_bind(server, "tcp://*:7766");
    
        char buffer[256] = { 0 };
    
        printf("%s
    ", "server listen 7766 ....");
        int i = 0;
        // [2]收发数据,先收再发
        while (1)
        {
            memset(buffer, 0, 256);
            zmq_recv(server, buffer, 256, 0);
            printf("recv: %s
    ", buffer);
            sleep(2);
            char szMsg[1024] = {0};
            snprintf(szMsg, sizeof(szMsg), " ack : %3d ", i++);
            zmq_send(server, szMsg, strlen(szMsg), 0);
            printf("send: %s
    ", szMsg);
        }
    
        zmq_close(server);
        zmq_ctx_destroy(ctx);
        return 0;
    }

     Client:

    #include <zmq.h>
    #include "stdio.h"
    #include <string.h>
    #include <unistd.h>
    
    int main(int argc, char * argv[])
    {
        // [0]创建对象
        void* ctx = zmq_ctx_new();
        void* server = zmq_socket(ctx, ZMQ_REQ);
        // [1]连接7766端口
        zmq_connect(server, "tcp://localhost:7766");
        char buffer[256] = { 0 };
        printf("%s
    ", "client connect 7766 ...");
    
        int i = 0;
        // [2]先发数据再收
        while (1)
        {
            char szMsg[1024] = {0};
            snprintf(szMsg, sizeof(szMsg), "hello world : %3d", i++);
            printf("send: %s
    ", szMsg);
            if (zmq_send(server, szMsg, strlen(szMsg), 0) < 0) {
                fprintf(stderr, "send message faild
    ");
            }
            sleep(2);
            memset(buffer, 0, 256);
            zmq_recv(server, buffer, 256, 0);
            printf("recv: %s
    ", buffer);
        }
    
        zmq_close(server);
        zmq_ctx_destroy(ctx);
        return 0;
    }

      

     使用REQ-REP套接字发送和接受消息是需要遵循一定规律的。客户端首先使用zmq_send()发送消息,再用zmq_recv()接收,如此循环。如果打乱了这个顺序(如连续发送两次)则会报错。类似地,服务端必须先进行接收,后进行发送。

    我们看看运行结果:

    我们首先运行client再运行server:

    zf@eappsvr-0:~/ds/zmq/test/req_rep> ./send
    client connect 7766 ...
    send: hello world :   0
    recv:  ack :   0
    zf@eappsvr-0:~/ds/zmq/test/req_rep> ./recv
    server listen 7766 ....
    recv: hello world :   0
    send:  ack :   0

    我们可以看到即使客户端先运行,也可以正常工作的,这就是zmq神奇的地方。

    让我简单介绍一下这两段程序到底做了什么。首先,他们创建了一个ZMQ上下文,然后是一个套接字。不要被这些陌生的名词吓到,后面我们都会讲到。服务端将REP套接字绑定到5555端口上,并开始等待请求,发出应答,如此循环。客户端则是发送请求并等待服务端的应答。

    这些代码背后其实发生了很多很多事情,但是程序员完全不必理会这些,只要知道这些代码短小精悍,极少出错,耐高压。这种通信模式我们称之为请求-应答模式,是ZMQ最直接的一种应用。

    下面我们试着在客户端连续发送两次:

     // [2]先发数据再收
        while (1)
        {
            char szMsg[1024] = {0};
            snprintf(szMsg, sizeof(szMsg), "hello world : %3d", i++);
            printf("send: %s
    ", szMsg);
            if (zmq_send(server, szMsg, strlen(szMsg), 0) < 0) {
                fprintf(stderr, "send message faild
    ");
            }
            if (zmq_send(server, szMsg, strlen(szMsg), 0) < 0) {
                fprintf(stderr, "send message faild
    ");
            }
            sleep(2);
            memset(buffer, 0, 256);
            zmq_recv(server, buffer, 256, 0);
            printf("recv: %s
    ", buffer);
        }
    // client
    client connect 7766 ...
    send: hello world :   0
    send message faild
    recv:  ack :   0 
    
    // server
    server listen 7766 ....
    recv: hello world :   0
    send:  ack :   0

    可以看到,第二次发送会失败,提问应答模式,严格控制着发送时序,必须发送-接收-发送-接收,打乱的话,会失败。

    关于字符串

    你可能注意到了我们上面的例子里, 其实客户端与服务端互相传输的数据里, 并没有包含C风格字符串最后一位的''.strlen并不会计算结尾的‘’。

    我们修改一下服务端buffer的初始值5:

     // [2]收发数据,先收再发
        while (1)
        {
            memset(buffer, 5, 256);
            zmq_recv(server, buffer, 256, 0);
            printf("recv: %s
    ", buffer);
            sleep(2);
            char szMsg[1024] = {0};
            snprintf(szMsg, sizeof(szMsg), " ack : %3d ", i++);
            zmq_send(server, szMsg, strlen(szMsg), 0);
            printf("send: %s
    ", szMsg);
        }
    server listen 7766 ....
    recv: hello world :   0
    XshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellXshellsend:  ack :   0 

    我们可以看到,接收数据就不是我们预想中的值,因为初始值为5,且接收的数据末尾非0,解析字符串就会出错。

    对于zmq来说,数据都是字节序列而已, 如何解释这些字节序列, 是使用者的责任. 比如上面, 我们需要在每次接收数据的时候记录接收的数据的大小, 并且在buffer中为接收到的数据之后的一个字节赋值为0, 即人为的把接收到的数据解释为字符串。

  • 相关阅读:
    判断字符串和null相等 if(keyword.equals("null"))
    去掉input text后面的叉
    设置标题小图标ico
    使用onclick跳转到其他页面。使用button跳转到指定url
    中文输入法不触发onkeyup事件的解决办法
    全选js实现
    修改数据库结构需要修改的部分
    1. 移动测试点
    2.7.2 元素定位:frame 内定位 driver.switch_to.frame()
    2.7.1 元素定位:selenium消息框处理 (alert、confirm、prompt)
  • 原文地址:https://www.cnblogs.com/vczf/p/12721543.html
Copyright © 2020-2023  润新知