C/C++网络编程总结与ZeroMQ(二)

2014-11-24 07:55:16 · 作者: · 浏览: 1

为啥又整出个ZeroMQ的C版本呢?

具本人所知,ZeroMQ作者在实现ZeroMQ后,有一天幡然醒悟“如果用C来实现ZeroMQ会不会更快呢?”所以他就用C语言重新实现了ZeroMQ,即nanomsg,目前是alpha2版本。官方网站:http://nanomsg.org/index.html

关于为什么要用C实现zeromq,其实上面是作者的杜撰。具体原因可以参照以下分析:)

为什么我希望用C而不是C++来实现ZeroMQ

为什么我希望用C而不是C++来实现ZeroMQ(第二篇)


从网上的资料来看,nanomsg确实比zeromq更快。

5.ZeorMQ优点,我为什么使用MQ?

1)使用简单,不需要部署服务器什么的,直接编译后作为一个动态库使用;

2) 编程开发简单

以下是zeromq的一个“helloword”示例:

Server

//
// Hello World server in C++
// Binds REP socket to tcp://*:5555
// Expects "Hello" from client, replies with "World"
//
#include 
  
   
#include 
   
     #include 
    
      #ifndef _WIN32 #include 
     
       #else #include <
      windows.h> #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' #ifndef _WIN32 sleep(1); #else Sleep (1); #endif // Send reply back to client zmq::message_t reply (5); memcpy ((void *) reply.data (), "World", 5); socket.send (reply); } return 0; }
     
    
   
  

Client

//
// Hello World client in C++
// Connects REQ socket to tcp://localhost:5555
// Sends "Hello" to server, expects "World" back
//
#include 
  
   
#include 
   
     #include 
    
      int main () { // Prepare our context and socket zmq::context_t context (1); zmq::socket_t socket (context, ZMQ_REQ); std::cout << "Connecting to hello world server..." << std::endl; socket.connect ("tcp://localhost:5555"); // Do 10 requests, waiting each time for a response for (int request_nbr = 0; request_nbr != 10; request_nbr++) { zmq::message_t request (6); memcpy ((void *) request.data (), "Hello", 5); std::cout << "Sending Hello " << request_nbr << "..." << std::endl; socket.send (request); // Get the reply. zmq::message_t reply; socket.recv (&reply); std::cout << "Received World " << request_nbr << std::endl; } return 0; }
    
   
  

很简单吧。对比其他MQ要么需要部署Server(ActiveMQ,RabbitMQ),要么复杂Boost::ASIO。

作为反面教材,Boost::ASIO中简单的echo-server例子如下:

Server

//
// blocking_tcp_echo_server.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include 
  
   
#include 
   
     #include 
    
      #include 
     
       #include 
      
        #include 
       
         using boost::asio::ip::tcp; const int max_length = 1024; typedef boost::shared_ptr
        
          socket_ptr; void session(socket_ptr sock) { try { for (;;) { char data[max_length]; boost::system::error_code error; size_t length = sock->read_some(boost::asio::buffer(data), error); if (error == boost::asio::error::eof) break; // Connection closed cleanly by peer. else if (error) throw boost::system::system_error(error); // Some other error. boost::asio::write(*sock, boost::asio::buffer(data, length)); } } catch (std::exception& e) { std::cerr << "Exception in thread: " << e.what() << "\n"; } } void server(boost::asio::io_service& io_service, unsigned short port) { tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port)); for (;;) { socket_ptr sock(new tcp::socket(io_service)); a.accept(*sock); boost::thread t(boost::bind(session, sock)); } } int main(int argc, char* argv[]) { try { if (argc != 2) { std::cerr << "Usage: blocking_tcp_echo_server 
         
          \n"; return 1; } boost::asio::io_service io_service; using namespace std; // For atoi. server(io_service, atoi(argv[1])); } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; }
         
        
       
      
     
    
   
  
Client

//
// blocking_tcp_echo_client.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#include 
  
   
#include 
   
     #include 
    
      #include 
     
       using boost::asio::ip::tcp; enum { max_length = 1024 }; int main(int argc, char* argv[]) { try { if (argc != 3) { std::cerr << "Usage: blocking_tcp_echo_client 
       
       
        \n"; return 1; } boost::asio::io_service io_service; tcp::resolver resolver(io_service); tcp::resolver::query query(tcp::v4(), argv[1], argv[2]); tcp::resolver::iterator iterator = resolver.resolve(query); tcp::socket s(io_service); boost::asio::connect(s, iterator); using namespace std; // For strlen. std::cout << "Enter message: "; char request[max_length]; std::cin.getline(request, max_length); size_t request_length = strlen(request); boost::asio::write(s, boost::asio::buffer(request, request_length)); char reply[max_length]; size_t reply_length = boost::asio::read(s, boost::asio::buffer(reply, request_length)); std::cout << "Reply is: "; std::cout.write(reply, reply_length); std::cout << "\n"; } catch (std::exception& e) { std::cerr << "Exception: " << e.what() << "\n"; } return 0; }
       
      
     
    
   
  
其实Boost算是简单的了,只是有对比才有进步嘛,ZeroMQ的代码仅有一半(不过这似乎说明不了什么问题)。

3)效率高(其实这个不是最重要的,最重要的是1、2)

为了让大伙儿有一个感性的认识,俺特地找来了消息队列软件的性能测评。这是某老外写的一篇帖子(在"这里"),不懂洋文的同学可以看"这里"。连帖子都懒得看的同学,可以直接看下图。


从图中可以明显看出,ZMQ 相比其它几款MQ,简直是鹤立鸡群啊!性能根本不在一个档次嘛。