Windows 为什么ZeroMQ PGM多播接收卡在两者之间&;不再接收数据包

Windows 为什么ZeroMQ PGM多播接收卡在两者之间&;不再接收数据包,windows,visual-c++,zeromq,jzmq,Windows,Visual C++,Zeromq,Jzmq,ZeroMQ(版本-ZeroMQ-4.1.6)PGM多播数据包接收卡在两者之间,即使发送方仍然发送数据包而没有任何问题 如果我们重新启动接收器,应用程序现在会接收数据包,但这不是一个解决方案。我在发送方和接收方都尝试了不同的ZMQ\u速率 问题: 发送方使用以下套接字选项发送了近300000个数据包,但接收方被夹在中间&没有接收到所有数据包。如果我们添加睡眠(2)——每次发送等待2ms,有时我们会收到所有的数据包,但这需要更多的时间 环境设置: (发送方和接收方使用D-Link交换机在单子网内连

ZeroMQ(版本-ZeroMQ-4.1.6)PGM多播数据包接收卡在两者之间,即使发送方仍然发送数据包而没有任何问题

如果我们重新启动接收器,应用程序现在会接收数据包,但这不是一个解决方案。我在发送方和接收方都尝试了不同的
ZMQ\u速率

问题:

发送方使用以下套接字选项发送了近300000个数据包,但接收方被夹在中间&没有接收到所有数据包。如果我们添加
睡眠(2)
——每次发送等待2ms,有时我们会收到所有的数据包,但这需要更多的时间

环境设置:

(发送方和接收方使用D-Link交换机在单子网内连接。媒体速度为1Gbps)

问题是什么

ZeroMQ PGM多播不是一个稳定的库吗

JZMQ Sender:
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket socket = context.socket(ZMQ.PUB);
socket.setRate(80000);
socket.setRecoveryInterval(60*60);
socket.setSendTimeOut(-1);
socket.setSendBufferSize(1024*64);
socket.bind("pgm://local_IP;239.255.0.20:30001");

byte[] bytesToSend = new byte[1024];
int count = 0;
while(count < 300000) {
    socket.send(bytesToSend, 0);
    count++;
}

------------------------------------------------
// ZMQCPP-PGM-receive.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <stdio.h>
#include "zmq.hpp"


int main(int argc, char* argv[]) {
    try {

         zmq::context_t context(1);

      // Socket to talk to server
         printf ("Connecting to server...");

         zmq::socket_t *s1 = new zmq::socket_t(context, ZMQ_SUB);

         int recvTimeout = 3000;
         s1->setsockopt(ZMQ_RCVTIMEO,&recvTimeout,sizeof(int));

         int recvRate = 80000;
         s1->setsockopt(ZMQ_RATE,&recvRate,sizeof(int));

         int recsec = 60 * 60;
      // s1->setsockopt(ZMQ_RECOVERY_IVL,&recsec,sizeof(recsec));

         s1->connect("pgm://local_IP;239.255.0.20:30001");

         s1->setsockopt (ZMQ_SUBSCRIBE, NULL, 0);

         printf ("done. \n");
         int seq=0;
         while(true) {

               zmq::message_t msgbuff;

               int ret = s1->recv(&msgbuff,0);
               if(!ret)
               {
                   printf ("Received not received timeout\n");
                   continue;
               }

               printf ("Seq(%d) Received data size=%d\n",seq,msgbuff.size());
               ++seq;
         }
    }
    catch( zmq::error_t &e )   {
           printf ("An error occurred: %s\n", e.what());
           return 1;
    }
    catch( std::exception &e ) {
           printf ("An error occurred: %s\n", e.what());
           return 1;
    }
    return 0;
}
JZMQ发送方:
ZMQ.Context=ZMQ.Context(1);
Socket=context.Socket(ZMQ.PUB);
插座设定值(80000);
socket.setRecoveryInterval(60*60);
socket.setSendTimeOut(-1);
socket.setSendBufferSize(1024*64);
socket.bind(“pgm://local_IP;239.255.0.20:30001");
byte[]bytesToSend=新字节[1024];
整数计数=0;
而(计数<300000){
socket.send(bytesToSend,0);
计数++;
}
------------------------------------------------
//ZMQCPP-PGM-receive.cpp:定义控制台应用程序的入口点。
//
#包括“stdafx.h”
#包括
#包括“zmq.hpp”
int main(int argc,char*argv[]){
试一试{
zmq::context\u t context(1);
//与服务器对话的套接字
printf(“连接到服务器…”);
zmq::socket\u t*s1=新的zmq::socket\u t(上下文,zmq\u SUB);
int recvTimeout=3000;
s1->setsockopt(ZMQ_RCVTIMEO和recvTimeout,sizeof(int));
int recvRate=80000;
s1->setsockopt(ZMQ_比率和回收率,sizeof(int));
int recsec=60*60;
//s1->setsockopt(ZMQ_RECOVERY_IVL和recsec,sizeof(recsec));
s1->连接(“pgm://local_IP;239.255.0.20:30001");
s1->setsockopt(ZMQ_SUBSCRIBE,NULL,0);
printf(“完成。\n”);
int-seq=0;
while(true){
zmq::message_t msgbuff;
int ret=s1->recv(&msgbuff,0);
如果(!ret)
{
printf(“已接收未接收超时\n”);
继续;
}
printf(“Seq(%d)接收的数据大小=%d\n”,Seq,msgbuff.size());
++序号;
}
}
捕获(zmq::错误\u t&e){
printf(“发生错误:%s\n”,例如what());
返回1;
}
捕获(标准::异常&e){
printf(“发生错误:%s\n”,例如what());
返回1;
}
返回0;
}
PGM稳定吗?
仅供参考:从V2.1.1开始工作,现在我们有稳定的4.2+ 这不是一个好的实践&我敢指责库维护人员在发布库之前没有彻底测试PGM/EPGM,或者在应用程序设计被充分理解之前的任何时候都没有做好开发工作,在实际部署生态系统的实际检查中,经过稳健设计和良好诊断以及性能/延迟测试,通常包括
{localhost | home subnet | remote network | remote host}


[PUB]-发送部件需要得到适当的注意: 如果没有其他内容,那么这部分文档就是警告,如果在一些模拟SLOC中出现资源管理不足的情况,则会敲响所有的警钟&吹响所有的口哨,而对于在非阻塞、超快速循环中发送的野蛮尝试,则应给予应有的注意:

ØMQ不保证套接字将接受多达
ZMQ_SNDHWM
的消息,根据套接字上的消息流,实际限制可能会低60-70%

所以,也许你的[PUB]发送者在丢失的消息被传送到网络之前就丢弃了这些消息

下一个警告来自O/S权限:

pgm的传输实现需要访问原始IP套接字。某些操作系统上可能需要额外的权限才能执行此操作。鼓励不需要与其他PGM实现直接互操作的应用程序使用不需要任何特权的epgm传输。


接下来是[SUB]-接收器: 更多的调整将有助于嗅探[PUB]发送方,类似于下面为[SUB]接收方建议的内联状态/跟踪工具:

------------------------------------------------
// ZMQCPP-PGM-receive.cpp : Defines the entry point for the console application.
//                          MODs: https://stackoverflow.com/q/44526517/3666197

#include "stdafx.h"
#include <stdio.h>
#include "zmq.hpp"

#include <chrono>                                                       // since C++ 11
typedef std::chrono::high_resolution_clock              nanoCLK;

#define ZMQ_IO_THREAD_POOL_SIZE                         8

#define ZMQ_AFINITY_PLAIN_ROUNDROBIN_UNMANAGED_RISKY    0
#define ZMQ_AFINITY_LO_PRIO_POOL                        0 | 1
#define ZMQ_AFINITY_HI_PRIO_POOL                        0 | 0 | 2
#define ZMQ_AFINITY_MC_EPGM_POOL                        0 | 0 | 0 | 4 | 8 | 0 | 0 | 64 | 128


int main( int argc, char* argv[] ) {

    auto RECV_start = nanoCLK::now();
    auto RECV_ret   = nanoCLK::now();
    auto RECV_last  = nanoCLK::now();
    auto TEST_start = nanoCLK::now();

    try {
           zmq::context_t context( ZMQ_IO_THREAD_POOL_SIZE );           printf ( "Connecting to server..." );
           int            major,  minor,  patch;
           zmq::version( &major, &minor, &patch );                      printf ( "Using ZeroMQ( %d.%d.%d )", major, minor, patch );

           zmq::socket_t *s1 = new zmq::socket_t( context, ZMQ_SUB );   // Socket to talk to server

           int zmqLinger   =       0,          // [  ms]
               zmqAffinity =       0,          // [   #]  mapper bitmap-onto-IO-thread-Pool (ref. #define-s above )

               recvBuffer  =       2 * 123456, // [   B]
               recvMaxSize =    9876,          // [   B]
               recvHwMark  =  123456,          // [   #]  max number of MSGs allowed to be Queued per connected Peer

               recvRate    =   80000 * 10,     // [kbps]
               recvTimeout =    3000,          // [  ms]  before ret EAGAIN { 0: NO_BLOCK | -1: INF | N: wait [ms] }
               recoverMSEC =      60 * 60      // [  ms]
               ;

           s1->setsockopt ( ZMQ_AFFINITY,     &zmqAffinity, sizeof(int) );
           s1->setsockopt ( ZMQ_LINGER,       &zmqLinger,   sizeof(int) );
           s1->setsockopt ( ZMQ_MAXMSGSIZE,   &recvMaxSize, sizeof(int) );
           s1->setsockopt ( ZMQ_RCVBUF,       &recvBuffer,  sizeof(int) );
           s1->setsockopt ( ZMQ_RCVHWM,       &recvHwMark,  sizeof(int) );
           s1->setsockopt ( ZMQ_RCVTIMEO,     &recvTimeout, sizeof(int) );
           s1->setsockopt ( ZMQ_RATE,         &recvRate,    sizeof(int) );
     //    s1->setsockopt ( ZMQ_RECOVERY_IVL, &recoverMSEC, sizeof(int) );

           s1->connect ( "pgm://local_IP;239.255.0.20:30001" );
           s1->setsockopt ( ZMQ_SUBSCRIBE, NULL, 0 );                   printf ( "done. \n" );

           int seq = 0;
           while( true ) {
                  zmq::message_t         msgbuff;                  RECV_start = nanoCLK::now(); RECV_last = RECV_ret;
                  int   ret = s1->recv( &msgbuff, 0 );             RECV_ret   = nanoCLK::now();
                  if ( !ret )                                           printf ( "[T0+ %14d [ns]]: [SUB] did not receive any message within set timeout(%d). RC == %d LOOP_ovhd == %6d [ns] RECV_wait == %10d [ns]\n", std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - TEST_start ).count(),           recvTimeout, ret, std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - RECV_last ).count(), std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - RECV_start ).count() );
                  else                                                  printf ( "[T0+ %14d [ns]]: [SUB] did now receive   a message SEQ#(%6d.) DATA[%6d] B. RC == %d LOOP_ovhd == %6d [ns] RECV_wait == %10d [ns]\n", std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - TEST_start ).count(), ++seq, msgbuff.size(), ret, std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - RECV_last ).count(), std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - RECV_start ).count() );
           }
    }
    catch( zmq::error_t   &e ) {                                        printf ( "[T0+ %14d [ns]]: [EXC.ZMQ] An error occurred: %s\nWill RET(1)", std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - TEST_start ).count(), e.what() );
           return 1;
    }
    catch( std::exception &e ) {                                        printf ( "[T0+ %14d [ns]]: [EXC.std] An error occurred: %s\nWill RET(1)", std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - TEST_start ).count(), e.what() );
           return 1;
    }
    return 0;
}
------------------------------------------------
//ZMQCPP-PGM-receive.cpp:定义控制台应用程序的入口点。
//MODs:https://stackoverflow.com/q/44526517/3666197
#包括“stdafx.h”
#包括
#包括“zmq.hpp”
包含/ /自C++ 11
typedef std::chrono::高分辨率时钟nanoCLK;
#定义ZMQ_IO_线程_池_大小8
#定义ZMQ_AFINITY_PLAIN_ROUNDROBIN_UNMANAGED_0
#定义ZMQ_AFINITY_LO_PRIO_池0 | 1
#定义ZMQ_AFINITY_HI_PRIO_池0 | 0 | 2
#定义ZMQ|u AFINITY|u MC|u EPGM|u池0 | 0 | 0 | 4 | 8 | 0 | 0 | 64 | 128
int main(int argc,char*argv[]){
auto RECV_start=nanoCLK::now();
auto RECV_ret=nanoCLK::now();
auto RECV_last=nanoCLK::now();
自动测试_start=nanoCLK::now();
试一试{
zmq::context_t context(zmq_IO_THREAD_POOL_SIZE);printf(“连接到服务器…”);
int大调、小调、面片;
zmq::version(&major,&minor,&patch);printf(“使用ZeroMQ(%d.%d.%d)”,major,minor,patch);
zmq::socket_t*s1=new zmq::socket_t(context,zmq_SUB);//与服务对话的套接字
------------------------------------------------
// ZMQCPP-PGM-receive.cpp : Defines the entry point for the console application.
//                          MODs: https://stackoverflow.com/q/44526517/3666197

#include "stdafx.h"
#include <stdio.h>
#include "zmq.hpp"

#include <chrono>                                                       // since C++ 11
typedef std::chrono::high_resolution_clock              nanoCLK;

#define ZMQ_IO_THREAD_POOL_SIZE                         8

#define ZMQ_AFINITY_PLAIN_ROUNDROBIN_UNMANAGED_RISKY    0
#define ZMQ_AFINITY_LO_PRIO_POOL                        0 | 1
#define ZMQ_AFINITY_HI_PRIO_POOL                        0 | 0 | 2
#define ZMQ_AFINITY_MC_EPGM_POOL                        0 | 0 | 0 | 4 | 8 | 0 | 0 | 64 | 128


int main( int argc, char* argv[] ) {

    auto RECV_start = nanoCLK::now();
    auto RECV_ret   = nanoCLK::now();
    auto RECV_last  = nanoCLK::now();
    auto TEST_start = nanoCLK::now();

    try {
           zmq::context_t context( ZMQ_IO_THREAD_POOL_SIZE );           printf ( "Connecting to server..." );
           int            major,  minor,  patch;
           zmq::version( &major, &minor, &patch );                      printf ( "Using ZeroMQ( %d.%d.%d )", major, minor, patch );

           zmq::socket_t *s1 = new zmq::socket_t( context, ZMQ_SUB );   // Socket to talk to server

           int zmqLinger   =       0,          // [  ms]
               zmqAffinity =       0,          // [   #]  mapper bitmap-onto-IO-thread-Pool (ref. #define-s above )

               recvBuffer  =       2 * 123456, // [   B]
               recvMaxSize =    9876,          // [   B]
               recvHwMark  =  123456,          // [   #]  max number of MSGs allowed to be Queued per connected Peer

               recvRate    =   80000 * 10,     // [kbps]
               recvTimeout =    3000,          // [  ms]  before ret EAGAIN { 0: NO_BLOCK | -1: INF | N: wait [ms] }
               recoverMSEC =      60 * 60      // [  ms]
               ;

           s1->setsockopt ( ZMQ_AFFINITY,     &zmqAffinity, sizeof(int) );
           s1->setsockopt ( ZMQ_LINGER,       &zmqLinger,   sizeof(int) );
           s1->setsockopt ( ZMQ_MAXMSGSIZE,   &recvMaxSize, sizeof(int) );
           s1->setsockopt ( ZMQ_RCVBUF,       &recvBuffer,  sizeof(int) );
           s1->setsockopt ( ZMQ_RCVHWM,       &recvHwMark,  sizeof(int) );
           s1->setsockopt ( ZMQ_RCVTIMEO,     &recvTimeout, sizeof(int) );
           s1->setsockopt ( ZMQ_RATE,         &recvRate,    sizeof(int) );
     //    s1->setsockopt ( ZMQ_RECOVERY_IVL, &recoverMSEC, sizeof(int) );

           s1->connect ( "pgm://local_IP;239.255.0.20:30001" );
           s1->setsockopt ( ZMQ_SUBSCRIBE, NULL, 0 );                   printf ( "done. \n" );

           int seq = 0;
           while( true ) {
                  zmq::message_t         msgbuff;                  RECV_start = nanoCLK::now(); RECV_last = RECV_ret;
                  int   ret = s1->recv( &msgbuff, 0 );             RECV_ret   = nanoCLK::now();
                  if ( !ret )                                           printf ( "[T0+ %14d [ns]]: [SUB] did not receive any message within set timeout(%d). RC == %d LOOP_ovhd == %6d [ns] RECV_wait == %10d [ns]\n", std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - TEST_start ).count(),           recvTimeout, ret, std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - RECV_last ).count(), std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - RECV_start ).count() );
                  else                                                  printf ( "[T0+ %14d [ns]]: [SUB] did now receive   a message SEQ#(%6d.) DATA[%6d] B. RC == %d LOOP_ovhd == %6d [ns] RECV_wait == %10d [ns]\n", std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - TEST_start ).count(), ++seq, msgbuff.size(), ret, std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - RECV_last ).count(), std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - RECV_start ).count() );
           }
    }
    catch( zmq::error_t   &e ) {                                        printf ( "[T0+ %14d [ns]]: [EXC.ZMQ] An error occurred: %s\nWill RET(1)", std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - TEST_start ).count(), e.what() );
           return 1;
    }
    catch( std::exception &e ) {                                        printf ( "[T0+ %14d [ns]]: [EXC.std] An error occurred: %s\nWill RET(1)", std::chrono::duration_cast<std::chrono::nanoseconds>( RECV_ret - TEST_start ).count(), e.what() );
           return 1;
    }
    return 0;
}