我正在使用多部分消息传递在C中使用ZeroMQ实现简单的 REQ-REP
模式。我的大部分邮件都严格分为四个部分(往返),但有一些例外。要执行该规则,我需要确定收到的多部分邮件的部分总数。知道是否小于等于4很容易。这是我的接收器功能:
#define BUFMAX 64 // Maximum size of text buffers
#define BUFRCV 63 // Maximum reception size of text buffers (reserve 1 space to add a terminal '\0')
char mpartstr[4][BUFMAX];
int recv_multi(void *socket,int *aremore)
// Receive upto the first 4 parts of a multipart message into mpartstr[][].
// Returns the number of parts read (upto 4) or <0 if there is an error.
// Returns -1 if there is an error with a zmq function.
// It sets aremore=1 if there are still more parts to read after the fourth
// part (or aremore=0 if not).
{
int len,rc,rcvmore,pdx,wrongpard=0;
size_t rcvmore_size = sizeof(rcvmore);
pdx=0;
len=zmq_recv(socket, mpartstr[pdx], BUFRCV, 0);
if(len==-1) return len;
mpartstr[pdx][len]='\0';
rc=zmq_getsockopt(socket,ZMQ_RCVMORE,&rcvmore,&rcvmore_size); if(rc) return -1;
pdx++;
if(rcvmore==0){*aremore=0; return pdx;}
while(rcvmore){
len=zmq_recv (socket, mpartstr[pdx], BUFRCV, 0); if(len==-1) return len; mpartstr[pdx][len]='\0';
rc=zmq_getsockopt(socket,ZMQ_RCVMORE,&rcvmore,&rcvmore_size); if(rc) return -1;
pdx++;
if(pdx==4) break;
}
*aremore=rcvmore;
return pdx;
}
很好。但是现在在我的main()
函数中,我通过查看aremore
的值来检查是否还有更多部分。在那些我不期望更多的情况下,我会将错误消息发送回发件人,但我发现,如果我不阅读多部分消息的所有部分,则ZeroMQ不喜欢它(它会读取其余部分下次我再次调用zmq_recv()
函数时,即使在我发送一条消息并期望有一个新的干净的多部分响应后,我也会再次调用此旧的多部分消息的一部分。
因此,我真正需要的是一种“冲洗”功能,用于清除消息的剩余部分,该消息包含要丢弃的4个以上部分。到目前为止,我唯一需要做的就是这样一个丑陋的任意蛮力用尽函数({aremore
的值开头为1-它是由上一个函数设置的):
int recv_exhaust(void *socket,int *aremore)
// Receive the remainder of a multipart message and discard the contents.
// Use this to clean out a multi-part 'inbox' from a wrongly sent message.
// Returns 0 on success
// Returns -1 on zmq function failure
// Returns -2 on failure to exhaust even after 1000 parts.
{
int len,rc,rcvmore,pdx;
size_t rcvmore_size = sizeof(rcvmore);
pdx=1;
rcvmore=*aremore;
while(rcvmore){
len=zmq_recv(socket, mpartstr[0], BUFRCV, 0); if(len==-1) return len;
rc=zmq_getsockopt(socket,ZMQ_RCVMORE,&rcvmore,&rcvmore_size); if(rc) return -1;
pdx++;
if(pdx>1000) return -2;
}
return 0;
}
如果没有专用的“冲洗器” API,那么如果我能够提前知道给定的多部分消息有多少部分,那么至少我可以摆脱任意的1000条消息限制。 ZeroMQ当然知道这一点,因为多部分消息是作为一个整体发送的。谁能指出我找到该信息的方式?还是那里有适当的“冲洗器”功能/方法? (对于标准C,请使用-而不是C ++ / C#等)。预先感谢。
答案 0 :(得分:1)
Q :有人可以指出我的查找方式吗?
是的
Q :那里是否有适当的“冲洗器”功能/方法?
是和否:
直到ZeroMoQ v2.x到v4.3.1为止,都没有对“冲洗器”的显式API调用
ZeroMQ设计提供的低延迟智能消息传递的美丽和力量是基于精心设计的Zen-of-Zero:始终偏爱性能而不是舒适性-零复制,零保修和其他范式表明
天真(我为此付出了很多辛苦,只能求助于使用原始的recv()...)“冲洗器”必须一直持续到 ZMQ_RCVMORE
< / strong>不会在多帧最后消息(或zmq_msg_more() == 0
确实符合)之外对NACK标记“超出”更多部分。尽管如此,所有这些操作仅执行指针处理,没有数据从RAM进行“移动/复制/读取”,仅分配了指针,因此它确实既快速又具有I / O效率:
int more;
size_t more_size = sizeof ( more );
do {
zmq_msg_t part; /* Create an empty ØMQ message to hold the message part */
int rc = zmq_msg_init (&part); assert (rc == 0 && "MSG_INIT failed" );
rc = zmq_msg_recv (&part, socket, 0); /* Block until a message is available to be received from socket */
assert (rc != -1 && "MSG_RECV failed" );
/* Determine if more message parts are to follow */
rc = zmq_getsockopt (socket, ZMQ_RCVMORE, &more, &more_size);
assert (rc == 0 && "GETSOCKOPT failed" );
zmq_msg_close (&part);
} while (more);
鉴于 RFC-23 / ZMTP 文件中记载的属性,只有少数(有线级遥测编码)担保:
1):所有邮件均已发送/发送:
2)多部分消息还获得内部(带内)遥测状态的“建议” :
{ 1: more-frames-follow| 0: no-more-frames }
{ 0: 8b-direct-octet | 1: 64b-"network-endian"-coded }
{ 0~255: direct-size | 0~2^63-1: 64b-"network-endian"-coded-size }
zmq_recv()
API与此类似:多部分邮件
ØMQ消息由1个或多个消息部分组成。每个消息部分本身就是一个独立的zmq_msg_t
。 ØMQ确保消息的原子传递:对等方应该接收消息的所有消息部分,或者根本不接收消息。 消息部分的总数不受可用存储空间的限制。
处理多部分消息的应用程序在调用zmq_msg_recv()确定是否还有其他部分要接收之后,必须使用ZMQ_RCVMORE zmq_getsockopt(3)选项。
无论在初读时看起来多么“丑陋”,内存中最坏的情况都是在多部分消息帧中存储大量的小消息。
确定的“摆脱错误”时间不是零,但是,紧凑高效的内部ZMTP遥测和低延迟流处理的好处是更重要的目标(并且已经实现)。
如有疑问,请首先对最坏情况进行基准测试:
a)“产生”大约1E9多部分消息帧,传输零大小的有效载荷(无数据,但所有消息框架)
b)“设置”是最简单的“拓扑” PUSH/PULL
c)“选择”您选择的 运输等级 -最佳无堆叠 { inproc:// | ipc:// | tipc:// | ... | vmci:// }
(我将对此进行压力测试)
d)秒表,当inproc://
进行POSACK验证时,在 ReferencePoint-S:
之间盲目机械零快捷方式“刷新” zmq_poll( ZMQ_POLLIN )
,这是由多部分组成的多部分消息中的最后一个被盲目的“冲洗器”马戏团所环绕。
在 ReferencePoint-E:
和 [S]
之间花费的纳秒级确实是金额最坏情况的证据“替罪羊” 进入了一个已知的“冲动”循环马戏团的时间。在现实的用例中,还有其他原因可能会花费更多的时间进行相同的操作。
不过, 责任发送这种{已知大小的|格式不正确的}-多帧BEAST ()是处理操作风险的根本原因,否则,延迟,高(几乎是线性的)可扩展性消息传递/信令框架。
零之禅的艺术使这种情况成为可能。多亏了MartinSÚSTRIK领导的Pieter HINTJENS和他的团队,我们都为能够继续处理他们的遗产而深表歉意。