zeromq -- 第一篇 初识zeromq

前言        
        
千言万语zeromq        
        
zeromq(0mq,或者zmq)看起来像一个嵌入式的网络库文件,但其功能如同一个并发框架;        
它提供了能够携带原子消息的套接字,可以实现进程内部,进程间,tcp以及多播通信;你        
可以使用诸如fan-out,pub-sub,任务分发以及请求响应等模式来连接套接口N-to-N;        
对于集群软件而言,它的效率非常高;它的异步IO模式可以提供可扩展的多核应用;同时,        
其提供多种语言的API,可以运行在绝大多数的操作系统上;zeromq是imatix公司开发的,        
是一款LGPLv3 的开源软件;        
        
        
开始        
        
        
先从hello world 这个程序开始来,服务端监听5555端口,当它接收到客户端的hello时,        
将会回复一个world给客户端;        
        
请求-响应 对套接字;客户端先调用 zmq_send() 然后调用 zmq_recv(),类似的服务端调用        
zmq_recv(),然后调用zmq_send()函数;下列为其参考语言:        
        
//        
//  Hello World server in C++        
//  Binds REP socket to tcp://*:5555        
//  Expects "Hello" from client, replies with "World"        
//        
#include <zmq.hpp>        
#include <string>        
#include <iostream>        
#ifndef _WIN32        
#include <unistd.h>        
#else        
#include <windows.h>        
        
#define sleep(n)    Sleep(n)        
#endif        
        
int main () {        
    //  Prepare our context and socket        
    zmq::context_t context (1);        
    zmq::socket_t socket (context, ZMQ_REP);        
    socket.bind ("tcp://*:5555");        
        
    while (true) {        
        zmq::message_t request;        
        
        //  Wait for next request from client        
        socket.recv (&request);        
        std::cout << "Received Hello" << std::endl;        
        
        //  Do some 'work'        
        sleep(1);        
        
        //  Send reply back to client        
        zmq::message_t reply (5);        
        memcpy ((void *) reply.data (), "World", 5);        
        socket.send (reply);        
    }        
    return 0;        
}        
      hwserver.cpp  
可以看到zeromq的语言非常类似c和c++语言,使用java或php语言,其代码将更加简单:        
        
<?php        
/*        
*  Hello World server        
*  Binds REP socket to tcp://*:5555        
*  Expects "Hello" from client, replies with "World"        
* @author  Ian Barber <ian(dot)barber(at)gmail(dot)com>        
*/        
        
$context = new ZMQContext(1);        
        
//  Socket to talk to clients        
$responder = new ZMQSocket($context, ZMQ::SOCKET_REP);        
$responder->bind("tcp://*:5555");        
        
while (true) {        
    //  Wait for next request from client        
    $request = $responder->recv();        
    printf ("Received request: [%s]\n", $request);        
        
    //  Do some 'work'        
    sleep (1);        
        
    //  Send reply back to client        
    $responder->send("World");        
}        
      hwserver.php  
        
//        
//  Hello World server in Java        
//  Binds REP socket to tcp://*:5555        
//  Expects "Hello" from client, replies with "World"        
//        
        
import org.zeromq.ZMQ;        
        
public class hwserver {        
        
    public static void main(String[] args) throws Exception {        
        ZMQ.Context context = ZMQ.context(1);        
        
        //  Socket to talk to clients        
        ZMQ.Socket responder = context.socket(ZMQ.REP);        
        responder.bind("tcp://*:5555");        
        
        while (!Thread.currentThread().isInterrupted()) {        
            // Wait for next request from the client        
            byte[] request = responder.recv(0);        
            System.out.println("Received Hello");        
        
            // Do some 'work'        
            Thread.sleep(1000);        
        
            // Send reply back to client        
            String reply = "World";        
            responder.send(reply.getBytes(), 0);        
        }        
        responder.close();        
        context.term();        
    }        
}        
        
      hwserver.java  
        
c++客户端程序如下所示:        
        
//  Hello World client        
#include <zmq.h>        
#include <string.h>        
#include <stdio.h>        
#include <unistd.h>        
        
int main (void)        
{        
    printf ("Connecting to hello world server…\n");        
    void *context = zmq_ctx_new ();        
    void *requester = zmq_socket (context, ZMQ_REQ);        
    zmq_connect (requester, "tcp://localhost:5555");        
        
    int request_nbr;        
    for (request_nbr = 0; request_nbr != 10; request_nbr++) {        
        char buffer [10];        
        printf ("Sending Hello %d…\n", request_nbr);        
        zmq_send (requester, "Hello", 5, 0);        
        zmq_recv (requester, buffer, 10, 0);        
        printf ("Received World %d\n", request_nbr);        
    }        
    zmq_close (requester);        
    zmq_ctx_destroy (context);        
    return 0;        
}        
        
        
        
这看起来非常的简单,但是zeromq还有更强大的功能;你可以一次性的向服务端发数以万计        
的客户端,它仍然会快速的处理;试着启动客户端然后启动服务端,来看看他是如何工作的;        
然后再思考下;        
        
如果你杀掉一个服务端,然后重启他,客户端将不会完全恢复;从当掉的进程恢复不是一件        
容易的事情;创建一个可靠的请求-响应工作流是非常复杂的,不过第四章的可靠的请求-响应        
模式可以解决他;        
        
这种场景下背后发生的事情总是会引起我们的注意,例如如何让代码更简洁,如何让代码更不容易        
当掉,即使在高负荷情况下;这就是请求-响应模式,或许是使用zeromq的最简单的方式,        
其类同于rpc调用或者客户端/服务端;        
        
        
如果你不告诉zeromq消息大小,zeromq是不会知道这些数据的;这就意味着,你必须安全的格式化        
数据,以便应用程序可以读取;对于对象或者复杂的数据来说这确实是一个工作量,就像Protocol Buffers        
但是对于字符串来说,你得小心点;        
        
在c语言中,字符串是以null来结束的;我们可以发送一个“hello”外加一个null字符;        
        
 zmq_send (requester, "Hello", 6, 0);       
        
然而,如果你用其他语言发送,可能不会包含一个null字符,例如我们用phython,        
        
 socket.send ("Hello")       
        
发送的字符将只有5个;        
        
如果你用c语言读取,你可能获取一个像字符串的东东,如果你幸运的话,可能收到的如发送的一样;        
如果客户端和服务端没有对此字符串格式达成协议,你很可能获得一个很尴尬的结果;        
        
如果你从zeromq(C语言)接收字符串,你可能无法相信它是安全终止结束的;每一次读取字符串,        
会为额外的字符申请空间,复制字符串,并在该字符串后添加null字符;        
        
我们制定一个这样的规则,zeromq字符串是由描述长度的,不需要后缀null字符的;按照最简单的例子        
zeromq字符串可以映射为一个消息帧,如同上面描述的长度和字符;        
        
c语言的代码如下所示:        
        
//  Receive ZeroMQ string from socket and convert into C string        
//  Chops string at 255 chars, if it's longer        
static char *        
s_recv (void *socket) {        
    char buffer [256];        
    int size = zmq_recv (socket, buffer, 255, 0);        
    if (size == -1)        
        return NULL;        
    if (size > 255)        
        size = 255;        
    buffer [size] = 0;        
    return strdup (buffer);        
}        

这种方式符合恰当的重复使用的精神,然后我们可以写出zeromq的send函数;这就是zhelpers.h        
文件,这可以让我们用c语音编写更短的zeromq的程序;不过,这确实有相当大的代码量,不过        
对于c程序员而言,就只当消遣了; 、

 

版本控制

由于 zeromq的版本更新也较为频繁;如果你遇到bug,可先在较新版本中查看是否已经修正,所以你最好知道
你在使用哪些版本;

#include <zmq.h>

int main (void)
{
int major, minor, patch;
zmq_version (&major, &minor, &patch);
printf ("Current 0MQ version is %d.%d.%d\n", major, minor, patch);
return 0;
}

      
 

转载于:https://my.oschina.net/u/2413521/blog/546380

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值