Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ zeromq:重置请求/代表套接字状态_C++_Sockets_Zeromq - Fatal编程技术网

C++ zeromq:重置请求/代表套接字状态

C++ zeromq:重置请求/代表套接字状态,c++,sockets,zeromq,C++,Sockets,Zeromq,当您使用简单的ZeroMQ REQ/REP模式时,您依赖于一个固定的send()->recv()/recv()->send()序列。 正如文章所描述的,当参与者在请求的中间断开连接时,会遇到麻烦,因为您不能只从另一个连接接收下一个请求开始,但状态机会强迫您向断开连接的请求发送请求。 自从写了上述文章以来,有没有出现一种更优雅的方法来解决这个问题 重新连接是否是解决此问题的唯一方法(除了不使用REQ/REP,而是使用另一种模式)有一种解决方案,即为所有调用添加超时。由于ZeroMQ本身并不真正提供

当您使用简单的ZeroMQ REQ/REP模式时,您依赖于一个固定的send()->recv()/recv()->send()序列。 正如文章所描述的,当参与者在请求的中间断开连接时,会遇到麻烦,因为您不能只从另一个连接接收下一个请求开始,但状态机会强迫您向断开连接的请求发送请求。 自从写了上述文章以来,有没有出现一种更优雅的方法来解决这个问题


重新连接是否是解决此问题的唯一方法(除了不使用REQ/REP,而是使用另一种模式)

有一种解决方案,即为所有调用添加超时。由于ZeroMQ本身并不真正提供简单的超时功能,因此我建议使用ZeroMQ套接字的子类,为所有重要调用添加超时参数


因此,您可以调用s.recv(timeout=5.0),而不是调用s.recv(),如果响应没有在5秒钟内返回,它将返回None并停止阻塞。当我遇到这个问题时,我做了一次徒劳的尝试

我现在正在研究这个问题,因为我正在重新安装一个遗留系统

我经常遇到“需要”了解连接状态的代码。然而,问题是我想转到库所提倡的消息传递范式

我发现了以下功能:

它所做的是监视传递给它的套接字并生成事件,然后将这些事件传递给“inproc”端点——此时,您可以添加处理代码来实际执行某些操作

这里还有一个示例(实际上是测试代码):

目前(可能在周末)我还没有给出任何具体的代码,但我的目的是响应连接和断开连接,以便我能够实际执行所需的任何逻辑重置

希望这能有所帮助,尽管引用了4.2文档,但我使用的是4.0.4,它似乎有这个功能 还有


注意到我注意到上面提到的Python,但是问题是C++的标记,所以我的答案来自……/P> < P>。好消息是,对于ZMQ 3和以后(现代时代),你可以在套接字上设置超时。正如其他人在其他地方所指出的,您必须在创建套接字之后但在连接之前执行以下操作:

zmq_req_socket.setsockopt(zmq.RCVTIMEO,500)#毫秒

然后,当您实际尝试接收回复时(在向REP套接字发送消息之后),您可以捕获将在超过超时时断言的错误:

 try:
   send( message, 0 )
   send_failed = False

 except zmq.Again:
   logging.warning( "Image send failed." )
   send_failed = True
然而!当这种情况发生时,正如其他地方所观察到的,您的套接字将处于一种有趣的状态,因为它仍然期待响应。在这一点上,我找不到任何可靠的工作,除了重新启动套接字。请注意,如果断开()套接字,然后重新连接(),它仍将处于此不良状态。因此,你需要

def reset_my_socket:
  zmq_req_socket.close()
  zmq_req_socket = zmq_context.socket( zmq.REQ )
  zmq_req_socket.setsockopt( zmq.RCVTIMEO, 500 ) # milliseconds
  zmq_req_socket.connect( zmq_endpoint )
您还将注意到,由于我关闭了套接字,因此接收超时选项“丢失”,因此在新套接字上设置该选项非常重要


我希望这有帮助。我希望这不是这个问题的最佳答案

由于被接受的答案让我感到非常难过,我做了一些研究,发现我们需要的所有东西实际上都在文档中

带有正确参数的
.setsockopt()
可以帮助您重置套接字状态机,而无需粗暴地破坏它,并在前一个死尸的基础上重建另一个套接字状态机

(是的,我喜欢这张照片)

ZMQ\u请求相关:
将回复与请求匹配
REQ
sockets的默认行为是依靠消息的顺序来匹配请求和响应,这通常就足够了。当此选项设置为
1
时,
REQ
套接字将在传出消息前面加上一个包含请求id的额外帧。这意味着完整消息是(
请求id
0
用户帧…
)。
REQ
套接字将丢弃所有不以这两个帧开头的传入消息。
选项值类型
int

选项值单位
0
1

默认值
0

适用的插座类型
ZMQ\u REQUE\u REQUE\u REQUE\u REQUE:
放松请求和回复之间的严格交替
默认情况下,
REQ
套接字不允许启动带有
zmq\u send(3)
的新请求,直到收到前一个请求的回复。当设置为
1
时,允许发送另一条消息,并具有断开与预期应答的对等方的基础连接的效果,从而在支持该消息的传输上触发重新连接尝试。请求-应答状态机被重置,新请求被发送到下一个可用对等方。
如果设置为
1
,还应启用
ZMQ\u REQ\u CORRELATE
,以确保请求和回复的正确匹配。否则,对中止请求的延迟回复可以报告为对替代请求的回复。
选项值类型
int

选项值单位
0
1

默认值
0

适用的插座类型


更新:我正在用这个优秀的资源更新这个答案:套接字编程很复杂,所以请查看本文中的参考资料

这里的答案似乎都不准确或有用。OP不是在寻找有关BSD套接字编程的信息。他试图找出如何在REP socket上的ZMQ中稳健地处理accept()ed客户端套接字故障
void zmq_setup(zmq::context_t** context, zmq::socket_t** socket, const char* endpoint)
{
    // Free old references.
    if(*socket != NULL)
    {
        (**socket).close();
        (**socket).~socket_t();
    }
    if(*context != NULL)
    {
        // Shutdown all previous server client-sockets.
        zmq_ctx_destroy((*context));
        (**context).~context_t();
    }

    *context = new zmq::context_t(1);
    *socket = new zmq::socket_t(**context, ZMQ_REP);

    // Enable TCP keep alive.
    int is_tcp_keep_alive = 1;
    (**socket).setsockopt(ZMQ_TCP_KEEPALIVE, &is_tcp_keep_alive, sizeof(is_tcp_keep_alive));

    // Only send 2 probes to check if client is still alive.
    int tcp_probe_no = 2;
    (**socket).setsockopt(ZMQ_TCP_KEEPALIVE_CNT, &tcp_probe_no, sizeof(tcp_probe_no));

    // How long does a con need to be "idle" for in seconds.
    int tcp_idle_timeout = 1;
    (**socket).setsockopt(ZMQ_TCP_KEEPALIVE_IDLE, &tcp_idle_timeout, sizeof(tcp_idle_timeout));

    // Time in seconds between individual keep alive probes.
    int tcp_probe_interval = 1;
    (**socket).setsockopt(ZMQ_TCP_KEEPALIVE_INTVL, &tcp_probe_interval, sizeof(tcp_probe_interval));

    // Discard pending messages in buf on close.
    int is_linger = 0;
    (**socket).setsockopt(ZMQ_LINGER, &is_linger, sizeof(is_linger));

    // TCP user timeout on unacknowledged send buffer
    int is_user_timeout = 2;
    (**socket).setsockopt(ZMQ_TCP_MAXRT, &is_user_timeout, sizeof(is_user_timeout));

    // Start internal enclave event server.
    printf("Host: Starting enclave event server\n");
    (**socket).bind(endpoint);
}
#include <signal.h>
#include <zmq.hpp>

// zmq_setup def here [...]

int main(int argc, char** argv) 
{
    // Ignore SIGPIPE signals.
    signal(SIGPIPE, SIG_IGN);
    // ... rest of your code after

    // (Could potentially also restart the server
    // sock on N SIGPIPEs if you're paranoid.)

    // Start server socket.
    const char* endpoint = "tcp://127.0.0.1:47357";
    zmq::context_t* context;
    zmq::socket_t* socket;
    zmq_setup(&context, &socket, endpoint);

    // Message buffers.
    zmq::message_t request;
    zmq::message_t reply;

    // ... rest of your socket code here
}
// E.g. skip broken accepted sockets (pseudo-code.)
while (1):
{
    try
    {
        if ((*socket).recv(&request)) == -1)
            throw -1;
    }
    catch (...)
    {
        // Prevent any endless error loops killing CPU.
        sleep(1)

        // Reset ZMQ state machine.
        try
        {
            zmq::message_t blank_reply = zmq::message_t();
            (*socket).send (blank_reply);
        }
        catch (...)
        {
            1;
        } 

        continue;
    }
import asyncio
import zmq
import zmq.asyncio

@asyncio.coroutine
def req(endpoint):
    ms = 2000 # In milliseconds.
    sock = ctx.socket(zmq.REQ)
    sock.setsockopt(zmq.SNDTIMEO, ms)
    sock.setsockopt(zmq.RCVTIMEO, ms)
    sock.setsockopt(zmq.LINGER, ms) # Discard pending buffered socket messages on close().
    sock.setsockopt(zmq.CONNECT_TIMEOUT, ms)

    # Connect the socket.
    # Connections don't strictly happen here.
    # ZMQ waits until the socket is used (which is confusing, I know.)
    sock.connect(endpoint)

    # Send some bytes.
    yield from sock.send(b"some bytes")

    # Recv bytes and convert to unicode.
    msg = yield from sock.recv()
    msg = msg.decode(u"utf-8")