ZeroMQ - 为一台服务器模拟多个客户端的标准套接字

Posted

技术标签:

【中文标题】ZeroMQ - 为一台服务器模拟多个客户端的标准套接字【英文标题】:ZeroMQ - Emulating standard socket for multiple clients to one server 【发布时间】:2019-08-21 08:59:27 【问题描述】:

我希望利用 ZeroMQ 来处理同时进入认证服务器的大量请求的队列。

我在 HPC 环境中,因此有大量计算节点都运行相同的启动程序,该启动程序与服务器一起证明。此服务器代码在前端节点上运行,在成功证明客户端后,将释放一个密钥,以便客户端解密作业数据。

目前使用的是标准套接字。当客户端最初向服务器发送内容时,使用来自sys/socket.haccept() 生成一个新套接字。这允许客户端和服务器在认证过程中相互发送多条消息(校验和等),然后在成功返回密钥之前。

ZeroMQ 的问题是附加命令不是必需的,因此不会为该特定证明创建辅助套接字。来自所有客户端的所有消息都以它们进入的任何顺序进行处理,导致多部分证明过程无法正常工作。我花了很长时间浏览指南并在谷歌上搜索以尝试找到类似的解决方案,但到目前为止还没有任何运气。

有没有一种方法可以利用 ZeroMQ 在此应用程序中提供与标准套接字相同的行为?

【问题讨论】:

ZMQ本质上是一个消息队列的实现。如果这不是您想要/需要的,那么为什么不坚持使用普通套接字呢? 当前实现确实使用普通套接字。我正在考虑适应使用 0MQ 的原因是允许它处理等待与 SGX 飞地证明的大量计算节点队列。 enclave 不是线程安全的,因此目前它一次只能处理一个客户端,从而导致队列形成。当我使用当前系统达到大约 200 个计算节点进程时,事情开始超时,并且一些节点无法证明导致整个作业失败。当我用谷歌搜索处理大型队列时,出现了 0MQ,因此我想看看我是否可以轻松地将它换成标准套接字 【参考方案1】:

Q : 有没有一种方法我可以利用 ZeroMQ 在这个应用程序中提供相同的行为作为标准插座?

ZeroMQ 是 distributed-systems 的 very smart and rather behaviour-oriented 信号/消息传递平台,而不是套接字。

鉴于您的意图是对 HPC 生态系统有价值,假设/指导使用某种工具的解决方案并且必须尽可能地弯曲它,以便它变得接近类似于原生行为,但是对于其他工具,似乎不是典型的 HPC 级方法。

HPC 代码通常经过精心设计,以提高计算成本效率(并为所有那些今天被允许不为终极性能和硬件资源的使用效率 :o) ) - 在这里,如果有人支付 ZeroMQ 实例化的费用,那么这些非零实例化成本和获得“只是”-a-socket-alike 似乎没有任何好处行为,以成本为代价,具有负面的性能收益,没有对智能的、集群范围的 ZeroMQ 服务(无论是 N+1 还是 N+M 冗余、低延迟智能节点间集群信令、密码学、廉价的以安全为动机的白名单,或任何可能代表任何额外 HPC 级项目利益的东西,这可能证明初始 ZeroMQ 实例化的成本是合理的)。


ZMQ_STREAM 的定义原型可能会提供一些工具,但是,参考。以上

ZMQ_STREAM 类型的套接字用于在使用tcp:// 传输时从非ØMQ 对等方发送和接收TCP 数据。 ZMQ_STREAM 套接字可以充当客户端和/或服务器,异步发送和/或接收 TCP 数据。 接收 TCP 数据时,ZMQ_STREAM 套接字应在将消息传递给应用程序之前,在消息前面添加一个包含原始对等方身份的消息部分。收到的消息在所有连接的对等点之间公平排队。 发送 TCP 数据时,ZMQ_STREAM 套接字应删除消息的第一部分并使用它来确定消息应路由到的对等方的身份,不可路由的消息将导致EHOSTUNREACHEAGAIN 错误。 要打开与服务器的连接,请使用 zmq_connect 调用,然后使用 ZMQ_IDENTITY zmq_getsockopt 调用获取套接字标识。 要关闭特定连接,请发送身份帧,后跟零长度消息(请参阅示例部分)。 建立连接后,应用程序将收到一条长度为零的消息。同样,当对端断开连接(或连接丢失)时,应用程序将收到一条长度为零的消息。 您必须先发送一个身份帧,然后再发送一个数据帧。 ZMQ_SNDMORE 标志对于标识帧是必需的,但在数据帧上被忽略。

ZMQ_STREAM 示例:

void *ctx = zmq_ctx_new ();                          assert (ctx     && "Context Instantiation Failed..." );
void *socket = zmq_socket (ctx, ZMQ_STREAM);         assert (socket  && "socket Instantiation Failed..." );
int rc = zmq_bind (socket, "tcp://*:8080");          assert (rc == 0 && "socket.bind() Failed..." );
uint8_t id [256];                                 /* Data structure to hold the ZMQ_STREAM ID */
size_t id_size = 256;
uint8_t raw [256];                                /* Data structure to hold the ZMQ_STREAM received data */
size_t raw_size = 256;
while (1) 
   id_size = zmq_recv (socket, id, 256, 0);          assert (id_size > 0 && "Get HTTP request; ID frame and then request; Failed..." )
   do 
        raw_size = zmq_recv (socket, raw, 256, 0);   assert (raw_size >= 0 && "socket.recv() Failed..." );
    while (raw_size == 256);

   char http_response [] =                        /* Prepares the response */
            "HTTP/1.0 200 OK\r\n"
            "Content-Type: text/plain\r\n"
            "\r\n"
            "Hello, World!";
   zmq_send (socket, id, id_size, ZMQ_SNDMORE);   /* Sends the ID frame followed by the response */
   zmq_send (socket, http_response, strlen (http_response), 0);
   zmq_send (socket, id, id_size, ZMQ_SNDMORE);   /* Closes the connection by sending the ID frame followed by a zero response */
   zmq_send (socket, 0, 0, 0);

zmq_close (socket);
zmq_ctx_destroy (ctx);

ZeroMQ zmq_getsockopt() 可以提供 POSIX/SOCKET 描述符,用于低级技巧

ZMQ_FD 选项应检索与指定套接字关联的文件描述符。返回的文件描述符可用于将套接字集成到现有的事件循环中; ØMQ 库应通过使文件描述符准备好读取,以边缘触发的方式通知套接字上的任何未决事件。 从返回的文件描述符中读取的能力并不一定表明消息可以从底层套接字读取或写入;应用程序必须通过随后检索ZMQ_EVENTS 选项来检索实际事件状态。 返回的文件描述符也在 zmq_sendzmq_recv 函数内部使用。由于描述符是边缘触发的,因此应用程序必须在每次调用zmq_sendzmq_recv 后更新ZMQ_EVENTS 的状态。 更明确地说: 在调用 zmq_send 之后,套接字可能变得可读(反之亦然),而不会触发文件描述符上的读取事件。 返回的文件描述符旨在用于 poll 或类似的系统调用only。应用程序绝不能尝试直接读取或写入数据,也不应尝试关闭它。 选项值类型:POSIX 系统上为int,Windows 上为 SOCKET


如需更多details on ZeroMQ tricks,请阅读此处已讨论的解决方案、性能基准、延迟削减细节和其他解决问题的技巧。

【讨论】:

感谢您的回复。我同意试图让 ZeroMQ 像标准套接字一样工作远非最佳,现在意识到我可能应该重新表述我最初的问题。我的最终目标是让服务器接受来自客户端的初始消息,然后专门与该客户端对话,直到它得到证明。这涉及来回发送许多消息。使用标准套接字,这很容易实现,因为当服务器接受客户端连接时会创建一个新套接字。有没有我可以在 ZeroMQ 中实现的方法来产生相同的结果? @McPhie - 欢迎来到 *** 社区。随意接受提供的最佳答案,并可以根据进一步需要打开另一个问题来调查问题或打开新的范例。 “爬行”这个话题并不是公平处理已经回答了你原来的问题的成员社区的标志。 *** 鼓励通过单击“投票”(灰色三角形 [此答案很有用])并接受所提供的、社区赞助的帮助中的最佳答案来表示 [谢谢]。书面感谢是礼貌的,但不符合 *** 网络礼仪

以上是关于ZeroMQ - 为一台服务器模拟多个客户端的标准套接字的主要内容,如果未能解决你的问题,请参考以下文章

为啥 ZeroMQ 服务器没有收到来自客户端的任何请求?

ZeroMQ 作业分配

具有多个客户端的 Obj-C 服务器

ZeroMQ:如何获取连接客户端的地址?

ZeroMQ REQ/REP 如何处理多个客户端?

如何使用 ZeroMQ 从 C# 客户端向 C++ 服务器发送消息