mirror of
https://github.com/zeromq/libzmq.git
synced 2025-01-31 14:39:55 +01:00
Merge pull request #1577 from hintjens/master
Various cleanups for CLIENT-SERVER sockets
This commit is contained in:
commit
fb57110b94
@ -157,6 +157,7 @@ check_function_exists(gethrtime HAVE_GETHRTIME)
|
||||
set(CMAKE_REQUIRED_INCLUDES )
|
||||
|
||||
add_definitions(-D_REENTRANT -D_THREAD_SAFE)
|
||||
add_definitions(-D_USING_CMAKE)
|
||||
|
||||
option(ENABLE_EVENTFD "Enable/disable eventfd" ZMQ_HAVE_EVENTFD)
|
||||
|
||||
|
@ -6,6 +6,7 @@ MAN3 = zmq_bind.3 zmq_unbind.3 zmq_connect.3 zmq_disconnect.3 zmq_close.3 \
|
||||
zmq_msg_init.3 zmq_msg_init_data.3 zmq_msg_init_size.3 \
|
||||
zmq_msg_move.3 zmq_msg_copy.3 zmq_msg_size.3 zmq_msg_data.3 zmq_msg_close.3 \
|
||||
zmq_msg_send.3 zmq_msg_recv.3 \
|
||||
zmq_msg_routing_id.3 zmq_msg_set_routing_id.3 \
|
||||
zmq_send.3 zmq_recv.3 zmq_send_const.3 \
|
||||
zmq_msg_get.3 zmq_msg_set.3 zmq_msg_more.3 zmq_msg_gets.3 \
|
||||
zmq_getsockopt.3 zmq_setsockopt.3 \
|
||||
|
@ -688,6 +688,17 @@ Default value:: 0 (leave to OS default)
|
||||
Applicable socket types:: all, when using TCP transports.
|
||||
|
||||
|
||||
ZMQ_THREADSAFE: Retrieve socket thread safety
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
The 'ZMQ_THREADSAFE' option shall retrieve a boolean value indicating whether
|
||||
or not the socket is threadsafe. Currently only 'ZMQ_CLIENT' sockets are
|
||||
threadsafe.
|
||||
|
||||
[horizontal]
|
||||
Option value type:: boolean
|
||||
Applicable socket types:: all
|
||||
|
||||
|
||||
ZMQ_TOS: Retrieve the Type-of-Service socket override status
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Retrieve the IP_TOS option for the socket.
|
||||
|
61
doc/zmq_msg_routing_id.txt
Normal file
61
doc/zmq_msg_routing_id.txt
Normal file
@ -0,0 +1,61 @@
|
||||
zmq_msg_routing_id(3)
|
||||
=====================
|
||||
|
||||
|
||||
NAME
|
||||
----
|
||||
zmq_msg_routing_id - return routing ID for message, if any
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
*uint32_t zmq_msg_routing_id (zmq_msg_t '*message');*
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _zmq_msg_routing_id()_ function returns the routing ID for the message,
|
||||
if any. The routing ID is set on all messages received from a 'ZMQ_SERVER'
|
||||
socket. To send a message to a 'ZMQ_SERVER' socket you must set the routing
|
||||
ID of a connected 'ZMQ_CLIENT' peer. Routing IDs are transient.
|
||||
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _zmq_msg_routing_id()_ function shall return zero if there is no routing
|
||||
ID, otherwise it shall return an unsigned 32-bit integer greater than zero.
|
||||
|
||||
|
||||
EXAMPLE
|
||||
-------
|
||||
.Receiving a client message and routing ID
|
||||
----
|
||||
void *ctx = zmq_ctx_new ();
|
||||
assert (ctx);
|
||||
|
||||
void *server = zmq_socket (ctx, ZMQ_SERVER);
|
||||
assert (server);
|
||||
int rc = zmq_bind (server, "tcp://127.0.0.1:8080");
|
||||
assert (rc == 0);
|
||||
|
||||
zmq_msg_t message;
|
||||
rc = zmq_msg_init (&message);
|
||||
assert (rc == 0);
|
||||
|
||||
// Receive a message from socket
|
||||
rc = zmq_msg_recv (server, &message, 0);
|
||||
assert (rc != -1);
|
||||
uint32_t routing_id = zmq_msg_routing_id (&message);
|
||||
assert (routing_id);
|
||||
----
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkzmq:zmq_msg_set_routing_id[3]
|
||||
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
This page was written by the 0MQ community. To make a change please
|
||||
read the 0MQ Contribution Policy at <http://www.zeromq.org/docs:contributing>.
|
46
doc/zmq_msg_set_routing_id.txt
Normal file
46
doc/zmq_msg_set_routing_id.txt
Normal file
@ -0,0 +1,46 @@
|
||||
zmq_msg_set_routing_id(3)
|
||||
=========================
|
||||
|
||||
|
||||
NAME
|
||||
----
|
||||
|
||||
zmq_msg_set_routing_id - set routing ID property on message
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
*int zmq_msg_set_routing_id (zmq_msg_t '*message', uint32_t 'routing_id');*
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
The _zmq_msg_set_routing_id()_ function sets the 'routing_id' specified, on the
|
||||
the message pointed to by the 'message' argument. The 'routing_id' must be
|
||||
greater than zero. To get a valid routing ID, you must receive a message
|
||||
from a 'ZMQ_SERVER' socket, and use the libzmq:zmq_msg_routing_id method.
|
||||
Routing IDs are transient.
|
||||
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _zmq_msg_set_routing_id()_ function shall return zero if successful. Otherwise it
|
||||
shall return `-1` and set 'errno' to one of the values defined below.
|
||||
|
||||
|
||||
ERRORS
|
||||
------
|
||||
*EINVAL*::
|
||||
The provided 'routing_id' is zero.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
--------
|
||||
linkzmq:zmq_msg_routing_id[3]
|
||||
linkzmq:zmq[7]
|
||||
|
||||
|
||||
AUTHORS
|
||||
-------
|
||||
This page was written by the 0MQ community. To make a change please
|
||||
read the 0MQ Contribution Policy at <http://www.zeromq.org/docs:contributing>.
|
@ -56,73 +56,45 @@ The following sections present the socket types defined by 0MQ, grouped by the
|
||||
general _messaging pattern_ which is built from related socket types.
|
||||
|
||||
|
||||
Request-reply pattern
|
||||
Client-server pattern
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
The request-reply pattern is used for sending requests from a ZMQ_REQ _client_
|
||||
to one or more ZMQ_REP _services_, and receiving subsequent replies to each
|
||||
request sent.
|
||||
|
||||
The request-reply pattern is formally defined by http://rfc.zeromq.org/spec:28.
|
||||
The client-server pattern is used to allow a single 'ZMQ_SERVER' _server_ talk
|
||||
to one or more 'ZMQ_CLIENT' _clients_. The client always starts the conversation,
|
||||
after which either peer can send messages asynchronously, to the other.
|
||||
|
||||
ZMQ_REQ
|
||||
^^^^^^^
|
||||
A socket of type 'ZMQ_REQ' is used by a _client_ to send requests to and
|
||||
receive replies from a _service_. This socket type allows only an alternating
|
||||
sequence of _zmq_send(request)_ and subsequent _zmq_recv(reply)_ calls. Each
|
||||
request sent is round-robined among all _services_, and each reply received is
|
||||
matched with the last issued request.
|
||||
The client-server pattern is formally defined by http://rfc.zeromq.org/spec:41.
|
||||
|
||||
If no services are available, then any send operation on the socket shall
|
||||
block until at least one _service_ becomes available. The REQ socket shall
|
||||
not discard messages.
|
||||
Note: this pattern deprecates the use of 'ZMQ_DEALER' and 'ZMQ_ROUTER' to build
|
||||
client-server architectures.
|
||||
|
||||
[horizontal]
|
||||
.Summary of ZMQ_REQ characteristics
|
||||
Compatible peer sockets:: 'ZMQ_REP', 'ZMQ_ROUTER'
|
||||
Direction:: Bidirectional
|
||||
Send/receive pattern:: Send, Receive, Send, Receive, ...
|
||||
Outgoing routing strategy:: Round-robin
|
||||
Incoming routing strategy:: Last peer
|
||||
Action in mute state:: Block
|
||||
|
||||
|
||||
ZMQ_REP
|
||||
^^^^^^^
|
||||
A socket of type 'ZMQ_REP' is used by a _service_ to receive requests from and
|
||||
send replies to a _client_. This socket type allows only an alternating
|
||||
sequence of _zmq_recv(request)_ and subsequent _zmq_send(reply)_ calls. Each
|
||||
request received is fair-queued from among all _clients_, and each reply sent
|
||||
is routed to the _client_ that issued the last request. If the original
|
||||
requester does not exist any more the reply is silently discarded.
|
||||
|
||||
[horizontal]
|
||||
.Summary of ZMQ_REP characteristics
|
||||
Compatible peer sockets:: 'ZMQ_REQ', 'ZMQ_DEALER'
|
||||
Direction:: Bidirectional
|
||||
Send/receive pattern:: Receive, Send, Receive, Send, ...
|
||||
Incoming routing strategy:: Fair-queued
|
||||
Outgoing routing strategy:: Last peer
|
||||
|
||||
|
||||
ZMQ_DEALER
|
||||
ZMQ_CLIENT
|
||||
^^^^^^^^^^
|
||||
A socket of type 'ZMQ_DEALER' is an advanced pattern used for extending
|
||||
request/reply sockets. Each message sent is round-robined among all connected
|
||||
peers, and each message received is fair-queued from all connected peers.
|
||||
A 'ZMQ_CLIENT' socket talks to a 'ZMQ_SERVER' socket. Either peer can connect,
|
||||
though the usual and recommended model is to bind the 'ZMQ_SERVER' and connect
|
||||
the 'ZMQ_CLIENT'.
|
||||
|
||||
When a 'ZMQ_DEALER' socket enters the 'mute' state due to having reached the
|
||||
high water mark for all peers, or if there are no peers at all, then any
|
||||
linkzmq:zmq_send[3] operations on the socket shall block until the mute
|
||||
state ends or at least one peer becomes available for sending; messages are not
|
||||
discarded.
|
||||
If the 'ZMQ_CLIENT' socket has established a connection, linkzmq:zmq_send[3]
|
||||
will accept messages, queue them, and send them as rapidly as the network
|
||||
allows. The outgoing buffer limit is defined by the high water mark for the
|
||||
socket. If the outgoing buffer is full, or if there is no connected peer,
|
||||
linkzmq:zmq_send[3] will block, by default. The 'ZMQ_CLIENT' socket will not
|
||||
drop messages.
|
||||
|
||||
When a 'ZMQ_DEALER' socket is connected to a 'ZMQ_REP' socket each message sent
|
||||
must consist of an empty message part, the _delimiter_, followed by one or more
|
||||
_body parts_.
|
||||
When a 'ZMQ_CLIENT' socket is connected to multiple 'ZMQ_SERVER' sockets,
|
||||
outgoing messages are distributed between connected peers on a round-robin
|
||||
basis. Likewise, the 'ZMQ_CLIENT' socket receives messages fairly from each
|
||||
connected peer. This usage is sensible only for stateless protocols.
|
||||
|
||||
'ZMQ_CLIENT' sockets are threadsafe and can be used from multiple threads
|
||||
at the same time. Note that replies from a 'ZMQ_SERVER' socket will go to
|
||||
the first client thread that calls libzmq:zmq_msg_recv. If you need to get
|
||||
replies back to the originating thread, use one 'ZMQ_CLIENT' socket per
|
||||
thread.
|
||||
|
||||
[horizontal]
|
||||
.Summary of ZMQ_DEALER characteristics
|
||||
Compatible peer sockets:: 'ZMQ_ROUTER', 'ZMQ_REP', 'ZMQ_DEALER'
|
||||
.Summary of ZMQ_CLIENT characteristics
|
||||
Compatible peer sockets:: 'ZMQ_SERVER'
|
||||
Direction:: Bidirectional
|
||||
Send/receive pattern:: Unrestricted
|
||||
Outgoing routing strategy:: Round-robin
|
||||
@ -130,38 +102,30 @@ Incoming routing strategy:: Fair-queued
|
||||
Action in mute state:: Block
|
||||
|
||||
|
||||
ZMQ_ROUTER
|
||||
ZMQ_SERVER
|
||||
^^^^^^^^^^
|
||||
A socket of type 'ZMQ_ROUTER' is an advanced socket type used for extending
|
||||
request/reply sockets. When receiving messages a 'ZMQ_ROUTER' socket shall
|
||||
prepend a message part containing the _identity_ of the originating peer to the
|
||||
message before passing it to the application. Messages received are fair-queued
|
||||
from among all connected peers. When sending messages a 'ZMQ_ROUTER' socket shall
|
||||
remove the first part of the message and use it to determine the _identity_ of
|
||||
the peer the message shall be routed to. If the peer does not exist anymore
|
||||
the message shall be silently discarded by default, unless 'ZMQ_ROUTER_MANDATORY'
|
||||
socket option is set to '1'.
|
||||
A 'ZMQ_SERVER' socket talks to a set of 'ZMQ_CLIENT' sockets. A 'ZMQ_SERVER'
|
||||
socket can only reply to an incoming message: the 'ZMQ_CLIENT' peer must
|
||||
always initiate a conversation.
|
||||
|
||||
When a 'ZMQ_ROUTER' socket enters the 'mute' state due to having reached the
|
||||
high water mark for all peers, then any messages sent to the socket shall be dropped
|
||||
until the mute state ends. Likewise, any messages routed to a peer for which
|
||||
the individual high water mark has been reached shall also be dropped.
|
||||
Each received message has a 'routing_id' that is a 32-bit unsigned integer.
|
||||
The application can fetch this with linkzmq:zmq_msg_routing_id[3]. To send
|
||||
a message to a given 'ZMQ_CLIENT' peer the application must set the peer's
|
||||
'routing_id' on the message, using linkzmq:zmq_msg_set_routing_id[3].
|
||||
|
||||
When a 'ZMQ_REQ' socket is connected to a 'ZMQ_ROUTER' socket, in addition to the
|
||||
_identity_ of the originating peer each message received shall contain an empty
|
||||
_delimiter_ message part. Hence, the entire structure of each received message
|
||||
as seen by the application becomes: one or more _identity_ parts, _delimiter_
|
||||
part, one or more _body parts_. When sending replies to a 'ZMQ_REQ' socket the
|
||||
application must include the _delimiter_ part.
|
||||
If the 'routing_id' is not specified, or does not refer to a connected client
|
||||
peer, the send call will fail with EHOSTUNREACH. If the outgoing buffer for
|
||||
the client peer is full, the send call will fail with EAGAIN. The 'ZMQ_SERVER'
|
||||
socket shall not drop messages, nor shall it block.
|
||||
|
||||
[horizontal]
|
||||
.Summary of ZMQ_ROUTER characteristics
|
||||
Compatible peer sockets:: 'ZMQ_DEALER', 'ZMQ_REQ', 'ZMQ_ROUTER'
|
||||
.Summary of ZMQ_SERVER characteristics
|
||||
Compatible peer sockets:: 'ZMQ_CLIENT'
|
||||
Direction:: Bidirectional
|
||||
Send/receive pattern:: Unrestricted
|
||||
Outgoing routing strategy:: See text
|
||||
Incoming routing strategy:: Fair-queued
|
||||
Action in mute state:: Drop
|
||||
Action in mute state:: Return EAGAIN
|
||||
|
||||
|
||||
Publish-subscribe pattern
|
||||
@ -373,6 +337,116 @@ Incoming routing strategy:: Fair-queued
|
||||
Action in mute state:: EAGAIN
|
||||
|
||||
|
||||
Request-reply pattern
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
The request-reply pattern is used for sending requests from a ZMQ_REQ _client_
|
||||
to one or more ZMQ_REP _services_, and receiving subsequent replies to each
|
||||
request sent.
|
||||
|
||||
The request-reply pattern is formally defined by http://rfc.zeromq.org/spec:28.
|
||||
|
||||
Note: this pattern will be deprecated in favor of the client-server pattern.
|
||||
|
||||
ZMQ_REQ
|
||||
^^^^^^^
|
||||
A socket of type 'ZMQ_REQ' is used by a _client_ to send requests to and
|
||||
receive replies from a _service_. This socket type allows only an alternating
|
||||
sequence of _zmq_send(request)_ and subsequent _zmq_recv(reply)_ calls. Each
|
||||
request sent is round-robined among all _services_, and each reply received is
|
||||
matched with the last issued request.
|
||||
|
||||
If no services are available, then any send operation on the socket shall
|
||||
block until at least one _service_ becomes available. The REQ socket shall
|
||||
not discard messages.
|
||||
|
||||
[horizontal]
|
||||
.Summary of ZMQ_REQ characteristics
|
||||
Compatible peer sockets:: 'ZMQ_REP', 'ZMQ_ROUTER'
|
||||
Direction:: Bidirectional
|
||||
Send/receive pattern:: Send, Receive, Send, Receive, ...
|
||||
Outgoing routing strategy:: Round-robin
|
||||
Incoming routing strategy:: Last peer
|
||||
Action in mute state:: Block
|
||||
|
||||
|
||||
ZMQ_REP
|
||||
^^^^^^^
|
||||
A socket of type 'ZMQ_REP' is used by a _service_ to receive requests from and
|
||||
send replies to a _client_. This socket type allows only an alternating
|
||||
sequence of _zmq_recv(request)_ and subsequent _zmq_send(reply)_ calls. Each
|
||||
request received is fair-queued from among all _clients_, and each reply sent
|
||||
is routed to the _client_ that issued the last request. If the original
|
||||
requester does not exist any more the reply is silently discarded.
|
||||
|
||||
[horizontal]
|
||||
.Summary of ZMQ_REP characteristics
|
||||
Compatible peer sockets:: 'ZMQ_REQ', 'ZMQ_DEALER'
|
||||
Direction:: Bidirectional
|
||||
Send/receive pattern:: Receive, Send, Receive, Send, ...
|
||||
Incoming routing strategy:: Fair-queued
|
||||
Outgoing routing strategy:: Last peer
|
||||
|
||||
|
||||
ZMQ_DEALER
|
||||
^^^^^^^^^^
|
||||
A socket of type 'ZMQ_DEALER' is an advanced pattern used for extending
|
||||
request/reply sockets. Each message sent is round-robined among all connected
|
||||
peers, and each message received is fair-queued from all connected peers.
|
||||
|
||||
When a 'ZMQ_DEALER' socket enters the 'mute' state due to having reached the
|
||||
high water mark for all peers, or if there are no peers at all, then any
|
||||
linkzmq:zmq_send[3] operations on the socket shall block until the mute
|
||||
state ends or at least one peer becomes available for sending; messages are not
|
||||
discarded.
|
||||
|
||||
When a 'ZMQ_DEALER' socket is connected to a 'ZMQ_REP' socket each message sent
|
||||
must consist of an empty message part, the _delimiter_, followed by one or more
|
||||
_body parts_.
|
||||
|
||||
[horizontal]
|
||||
.Summary of ZMQ_DEALER characteristics
|
||||
Compatible peer sockets:: 'ZMQ_ROUTER', 'ZMQ_REP', 'ZMQ_DEALER'
|
||||
Direction:: Bidirectional
|
||||
Send/receive pattern:: Unrestricted
|
||||
Outgoing routing strategy:: Round-robin
|
||||
Incoming routing strategy:: Fair-queued
|
||||
Action in mute state:: Block
|
||||
|
||||
|
||||
ZMQ_ROUTER
|
||||
^^^^^^^^^^
|
||||
A socket of type 'ZMQ_ROUTER' is an advanced socket type used for extending
|
||||
request/reply sockets. When receiving messages a 'ZMQ_ROUTER' socket shall
|
||||
prepend a message part containing the _identity_ of the originating peer to the
|
||||
message before passing it to the application. Messages received are fair-queued
|
||||
from among all connected peers. When sending messages a 'ZMQ_ROUTER' socket shall
|
||||
remove the first part of the message and use it to determine the _identity_ of
|
||||
the peer the message shall be routed to. If the peer does not exist anymore
|
||||
the message shall be silently discarded by default, unless 'ZMQ_ROUTER_MANDATORY'
|
||||
socket option is set to '1'.
|
||||
|
||||
When a 'ZMQ_ROUTER' socket enters the 'mute' state due to having reached the
|
||||
high water mark for all peers, then any messages sent to the socket shall be dropped
|
||||
until the mute state ends. Likewise, any messages routed to a peer for which
|
||||
the individual high water mark has been reached shall also be dropped.
|
||||
|
||||
When a 'ZMQ_REQ' socket is connected to a 'ZMQ_ROUTER' socket, in addition to the
|
||||
_identity_ of the originating peer each message received shall contain an empty
|
||||
_delimiter_ message part. Hence, the entire structure of each received message
|
||||
as seen by the application becomes: one or more _identity_ parts, _delimiter_
|
||||
part, one or more _body parts_. When sending replies to a 'ZMQ_REQ' socket the
|
||||
application must include the _delimiter_ part.
|
||||
|
||||
[horizontal]
|
||||
.Summary of ZMQ_ROUTER characteristics
|
||||
Compatible peer sockets:: 'ZMQ_DEALER', 'ZMQ_REQ', 'ZMQ_ROUTER'
|
||||
Direction:: Bidirectional
|
||||
Send/receive pattern:: Unrestricted
|
||||
Outgoing routing strategy:: See text
|
||||
Incoming routing strategy:: Fair-queued
|
||||
Action in mute state:: Drop
|
||||
|
||||
|
||||
RETURN VALUE
|
||||
------------
|
||||
The _zmq_socket()_ function shall return an opaque handle to the newly created
|
||||
|
@ -228,7 +228,7 @@ ZMQ_EXPORT int zmq_msg_get (zmq_msg_t *msg, int property);
|
||||
ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int property, int optval);
|
||||
ZMQ_EXPORT const char *zmq_msg_gets (zmq_msg_t *msg, const char *property);
|
||||
ZMQ_EXPORT int zmq_msg_set_routing_id (zmq_msg_t *msg, uint32_t routing_id);
|
||||
ZMQ_EXPORT uint32_t zmq_msg_get_routing_id(zmq_msg_t *msg);
|
||||
ZMQ_EXPORT uint32_t zmq_msg_routing_id (zmq_msg_t *msg);
|
||||
|
||||
|
||||
/******************************************************************************/
|
||||
|
@ -54,8 +54,6 @@ void zmq::client_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
|
||||
|
||||
int zmq::client_t::xsend (msg_t *msg_)
|
||||
{
|
||||
zmq_assert(!(msg_->flags () & msg_t::more));
|
||||
|
||||
return lb.sendpipe (msg_, NULL);
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,8 @@ const char *zmq::mechanism_t::socket_type_string (int socket_type) const
|
||||
{
|
||||
static const char *names [] = {"PAIR", "PUB", "SUB", "REQ", "REP",
|
||||
"DEALER", "ROUTER", "PULL", "PUSH",
|
||||
"XPUB", "XSUB", "STREAM", "SERVER", "CLIENT"};
|
||||
"XPUB", "XSUB", "STREAM",
|
||||
"SERVER", "CLIENT"};
|
||||
zmq_assert (socket_type >= 0 && socket_type <= 13);
|
||||
return names [socket_type];
|
||||
}
|
||||
@ -190,7 +191,7 @@ bool zmq::mechanism_t::check_socket_type (const std::string& type_) const
|
||||
case ZMQ_SERVER:
|
||||
return type_ == "CLIENT";
|
||||
case ZMQ_CLIENT:
|
||||
return type_ == "CLIENT" || type_ == "SERVER";
|
||||
return type_ == "SERVER";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -504,9 +504,13 @@ uint32_t zmq::msg_t::get_routing_id()
|
||||
|
||||
int zmq::msg_t::set_routing_id (uint32_t routing_id_)
|
||||
{
|
||||
if (routing_id_) {
|
||||
u.base.routing_id = routing_id_;
|
||||
return 0;
|
||||
}
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
zmq::atomic_counter_t *zmq::msg_t::refcnt()
|
||||
{
|
||||
|
@ -104,6 +104,7 @@ int zmq::router_t::xsetsockopt (int option_, const void *optval_,
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case ZMQ_ROUTER_RAW:
|
||||
if (is_int && value >= 0) {
|
||||
raw_socket = (value != 0);
|
||||
|
@ -54,6 +54,9 @@ void zmq::server_t::xattach_pipe (pipe_t *pipe_, bool subscribe_to_all_)
|
||||
zmq_assert (pipe_);
|
||||
|
||||
uint32_t routing_id = next_rid++;
|
||||
if (!routing_id)
|
||||
routing_id = next_rid++; // Never use RID zero
|
||||
|
||||
pipe_->set_routing_id (routing_id);
|
||||
// Add the record into output pipes lookup table
|
||||
outpipe_t outpipe = {pipe_, true};
|
||||
@ -90,8 +93,6 @@ void zmq::server_t::xwrite_activated (pipe_t *pipe_)
|
||||
|
||||
int zmq::server_t::xsend (msg_t *msg_)
|
||||
{
|
||||
zmq_assert(!(msg_->flags () & msg_t::more));
|
||||
|
||||
// Find the pipe associated with the routing stored in the message.
|
||||
uint32_t routing_id = msg_->get_routing_id ();
|
||||
outpipes_t::iterator it = outpipes.find (routing_id);
|
||||
@ -113,9 +114,10 @@ int zmq::server_t::xsend (msg_t *msg_)
|
||||
// Message failed to send - we must close it ourselves.
|
||||
int rc = msg_->close ();
|
||||
errno_assert (rc == 0);
|
||||
} else {
|
||||
it->second.pipe->flush ();
|
||||
}
|
||||
else
|
||||
it->second.pipe->flush ();
|
||||
|
||||
|
||||
// Detach the message from the data buffer.
|
||||
int rc = msg_->init ();
|
||||
|
@ -689,7 +689,7 @@ int zmq_msg_set_routing_id (zmq_msg_t *msg_, uint32_t routing_id_)
|
||||
return ((zmq::msg_t *) msg_)->set_routing_id (routing_id_);
|
||||
}
|
||||
|
||||
uint32_t zmq_msg_get_routing_id(zmq_msg_t *msg_)
|
||||
uint32_t zmq_msg_routing_id (zmq_msg_t *msg_)
|
||||
{
|
||||
return ((zmq::msg_t *) msg_)->get_routing_id ();
|
||||
}
|
||||
|
@ -38,14 +38,14 @@ int main (void)
|
||||
assert (ctx);
|
||||
|
||||
void *client = zmq_socket (ctx, ZMQ_CLIENT);
|
||||
void *dealer = zmq_socket (ctx, ZMQ_DEALER);
|
||||
void *server = zmq_socket (ctx, ZMQ_SERVER);
|
||||
|
||||
int rc;
|
||||
|
||||
rc = zmq_bind (client, "inproc://serverdropmore");
|
||||
assert (rc == 0);
|
||||
|
||||
rc = zmq_connect (dealer, "inproc://serverdropmore");
|
||||
rc = zmq_connect (server, "inproc://serverdropmore");
|
||||
assert (rc == 0);
|
||||
|
||||
zmq_msg_t msg;
|
||||
@ -53,28 +53,28 @@ int main (void)
|
||||
assert (rc == 0);
|
||||
|
||||
// we will send 2 3-frames messages and then single frame message, only last one should be received
|
||||
rc = send_msg (&msg, dealer, ZMQ_SNDMORE, 1);
|
||||
rc = send_msg (&msg, client, ZMQ_SNDMORE, 1);
|
||||
assert(rc == 1);
|
||||
|
||||
rc = send_msg (&msg, dealer, ZMQ_SNDMORE, 2);
|
||||
rc = send_msg (&msg, client, ZMQ_SNDMORE, 2);
|
||||
assert(rc == 1);
|
||||
|
||||
rc = send_msg (&msg, dealer, 0, 3);
|
||||
rc = send_msg (&msg, client, 0, 3);
|
||||
assert(rc == 1);
|
||||
|
||||
rc = send_msg (&msg, dealer, ZMQ_SNDMORE, 4);
|
||||
rc = send_msg (&msg, client, ZMQ_SNDMORE, 4);
|
||||
assert(rc == 1);
|
||||
|
||||
rc = send_msg (&msg, dealer, ZMQ_SNDMORE, 5);
|
||||
rc = send_msg (&msg, client, ZMQ_SNDMORE, 5);
|
||||
assert(rc == 1);
|
||||
|
||||
rc = send_msg (&msg, dealer, 0, 6);
|
||||
rc = send_msg (&msg, client, 0, 6);
|
||||
assert(rc == 1);
|
||||
|
||||
rc = send_msg (&msg, dealer, 0, 7);
|
||||
rc = send_msg (&msg, client, 0, 7);
|
||||
assert(rc == 1);
|
||||
|
||||
rc = zmq_msg_recv (&msg, client, 0);
|
||||
rc = zmq_msg_recv (&msg, server, 0);
|
||||
assert (rc == 1);
|
||||
|
||||
assert (zmq_msg_more (&msg) == 0);
|
||||
@ -88,7 +88,7 @@ int main (void)
|
||||
rc = zmq_close (client);
|
||||
assert (rc == 0);
|
||||
|
||||
rc = zmq_close (dealer);
|
||||
rc = zmq_close (server);
|
||||
assert (rc == 0);
|
||||
|
||||
rc = zmq_ctx_term (ctx);
|
||||
@ -100,12 +100,10 @@ int main (void)
|
||||
int send_msg (zmq_msg_t *msg, void *s, int flags, int value)
|
||||
{
|
||||
int rc = zmq_msg_close (msg);
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
zmq_msg_init_size (msg, 1);
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
|
@ -38,9 +38,7 @@ int main (void)
|
||||
void *server = zmq_socket (ctx, ZMQ_SERVER);
|
||||
void *client = zmq_socket (ctx, ZMQ_CLIENT);
|
||||
|
||||
int rc;
|
||||
|
||||
rc = zmq_bind (server, "tcp://127.0.0.1:5560");
|
||||
int rc = zmq_bind (server, "tcp://127.0.0.1:5560");
|
||||
assert (rc == 0);
|
||||
|
||||
rc = zmq_connect (client, "tcp://127.0.0.1:5560");
|
||||
@ -61,7 +59,7 @@ int main (void)
|
||||
rc = zmq_msg_recv (&msg, server, 0);
|
||||
assert (rc == 1);
|
||||
|
||||
uint32_t routing_id = zmq_msg_get_routing_id(&msg);
|
||||
uint32_t routing_id = zmq_msg_routing_id (&msg);
|
||||
assert (routing_id != 0);
|
||||
|
||||
rc = zmq_msg_close(&msg);
|
||||
|
@ -38,7 +38,7 @@ int main (void)
|
||||
assert (ctx);
|
||||
|
||||
void *server = zmq_socket (ctx, ZMQ_SERVER);
|
||||
void *client = zmq_socket (ctx, ZMQ_DEALER);
|
||||
void *client = zmq_socket (ctx, ZMQ_CLIENT);
|
||||
|
||||
int rc;
|
||||
|
||||
@ -100,12 +100,10 @@ int main (void)
|
||||
int send_msg (zmq_msg_t *msg, void *s, int flags, int value)
|
||||
{
|
||||
int rc = zmq_msg_close (msg);
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
zmq_msg_init_size (msg, 1);
|
||||
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
|
@ -29,8 +29,18 @@
|
||||
|
||||
#include "testutil.hpp"
|
||||
|
||||
void worker1(void* s);
|
||||
void worker2(void* s);
|
||||
// Client threads loop on send/recv until told to exit
|
||||
void client_thread (void *client)
|
||||
{
|
||||
char data = 0;
|
||||
for (int count = 0; count < 100000; count++) {
|
||||
int rc = zmq_send (client, &data, 1, 0);
|
||||
assert (rc == 1);
|
||||
}
|
||||
data = 1;
|
||||
int rc = zmq_send (client, &data, 1, 0);
|
||||
assert (rc == 1);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
@ -38,62 +48,32 @@ int main (void)
|
||||
void *ctx = zmq_ctx_new ();
|
||||
assert (ctx);
|
||||
|
||||
void *client = zmq_socket (ctx, ZMQ_CLIENT);
|
||||
void *client2 = zmq_socket (ctx, ZMQ_CLIENT);
|
||||
void *server = zmq_socket (ctx, ZMQ_SERVER);
|
||||
int rc = zmq_bind (server, "tcp://127.0.0.1:5560");
|
||||
assert (rc == 0);
|
||||
|
||||
void *client = zmq_socket (ctx, ZMQ_CLIENT);
|
||||
int thread_safe;
|
||||
size_t size = sizeof (int);
|
||||
|
||||
zmq_getsockopt (client, ZMQ_THREAD_SAFE, &thread_safe, &size);
|
||||
|
||||
assert (thread_safe == 1);
|
||||
|
||||
int rc;
|
||||
|
||||
rc = zmq_bind (client, "tcp://127.0.0.1:5560");
|
||||
rc = zmq_connect (client, "tcp://127.0.0.1:5560");
|
||||
assert (rc == 0);
|
||||
|
||||
rc = zmq_connect (client2, "tcp://127.0.0.1:5560");
|
||||
assert (rc == 0);
|
||||
void *t1 = zmq_threadstart (client_thread, client);
|
||||
void *t2 = zmq_threadstart (client_thread, client);
|
||||
|
||||
void* t1 = zmq_threadstart(worker1, client2);
|
||||
void* t2 = zmq_threadstart(worker2, client2);
|
||||
|
||||
char data[1];
|
||||
data[0] = 0;
|
||||
|
||||
for (int i=0; i < 10; i++) {
|
||||
rc = zmq_send_const(client, data, 1, 0);
|
||||
assert (rc == 1);
|
||||
|
||||
rc = zmq_send_const(client, data, 1, 0);
|
||||
assert(rc == 1);
|
||||
|
||||
char a, b;
|
||||
|
||||
rc = zmq_recv(client, &a, 1, 0);
|
||||
assert(rc == 1);
|
||||
|
||||
rc = zmq_recv(client, &b, 1, 0);
|
||||
assert(rc == 1);
|
||||
|
||||
// make sure they came from different threads
|
||||
assert((a == 1 && b == 2) || (a == 2 && b == 1));
|
||||
char data;
|
||||
int threads_completed = 0;
|
||||
while (threads_completed < 2) {
|
||||
zmq_recv (server, &data, 1, 0);
|
||||
if (data == 1)
|
||||
threads_completed++; // Thread ended
|
||||
}
|
||||
|
||||
// make the thread exit
|
||||
data[0] = 1;
|
||||
|
||||
rc = zmq_send_const(client, data, 1, 0);
|
||||
assert (rc == 1);
|
||||
|
||||
rc = zmq_send_const(client, data, 1, 0);
|
||||
assert(rc == 1);
|
||||
|
||||
zmq_threadclose (t1);
|
||||
zmq_threadclose (t2);
|
||||
|
||||
rc = zmq_close (client2);
|
||||
rc = zmq_close (server);
|
||||
assert (rc == 0);
|
||||
|
||||
rc = zmq_close (client);
|
||||
@ -104,59 +84,3 @@ int main (void)
|
||||
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
void worker1(void* s)
|
||||
{
|
||||
const char worker_id = 1;
|
||||
char c;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int rc = zmq_recv(s, &c,1, 0);
|
||||
assert(rc == 1);
|
||||
|
||||
if (c == 0)
|
||||
{
|
||||
msleep(100);
|
||||
rc = zmq_send_const(s,&worker_id, 1, 0);
|
||||
assert(rc == 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we got exit request
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void worker2(void* s)
|
||||
{
|
||||
const char worker_id = 2;
|
||||
char c;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int rc = zmq_recv(s, &c,1, 0);
|
||||
assert(rc == 1);
|
||||
|
||||
assert(c == 1 || c == 0);
|
||||
|
||||
if (c == 0)
|
||||
{
|
||||
msleep(100);
|
||||
rc = zmq_send_const(s,&worker_id, 1, 0);
|
||||
assert(rc == 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// we got exit request
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -32,7 +32,11 @@
|
||||
|
||||
#include "../include/zmq.h"
|
||||
#include "../src/stdint.hpp"
|
||||
#ifdef USING_CMAKE
|
||||
# include "platform.hpp"
|
||||
#else
|
||||
# include "../src/platform.hpp"
|
||||
#endif
|
||||
|
||||
// This defines the settle time used in tests; raise this if we
|
||||
// get test failures on slower systems due to binds/connects not
|
||||
@ -60,7 +64,6 @@
|
||||
|
||||
// Bounce a message from client to server and back
|
||||
// For REQ/REP or DEALER/DEALER pairs only
|
||||
|
||||
void
|
||||
bounce (void *server, void *client)
|
||||
{
|
||||
@ -116,7 +119,6 @@ bounce (void *server, void *client)
|
||||
|
||||
// Same as bounce, but expect messages to never arrive
|
||||
// for security or subscriber reasons.
|
||||
|
||||
void
|
||||
expect_bounce_fail (void *server, void *client)
|
||||
{
|
||||
@ -193,7 +195,9 @@ const char *SEQ_END = (const char *) 1;
|
||||
// Sends a message composed of frames that are C strings or null frames.
|
||||
// The list must be terminated by SEQ_END.
|
||||
// Example: s_send_seq (req, "ABC", 0, "DEF", SEQ_END);
|
||||
void s_send_seq (void *socket, ...)
|
||||
|
||||
void
|
||||
s_send_seq (void *socket, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start (ap, socket);
|
||||
@ -222,7 +226,9 @@ void s_send_seq (void *socket, ...)
|
||||
// the given data which can be either C strings or 0 for a null frame.
|
||||
// The list must be terminated by SEQ_END.
|
||||
// Example: s_recv_seq (rep, "ABC", 0, "DEF", SEQ_END);
|
||||
void s_recv_seq (void *socket, ...)
|
||||
|
||||
void
|
||||
s_recv_seq (void *socket, ...)
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
@ -260,7 +266,8 @@ void s_recv_seq (void *socket, ...)
|
||||
|
||||
|
||||
// Sets a zero linger period on a socket and closes it.
|
||||
void close_zero_linger (void *socket)
|
||||
void
|
||||
close_zero_linger (void *socket)
|
||||
{
|
||||
int linger = 0;
|
||||
int rc = zmq_setsockopt (socket, ZMQ_LINGER, &linger, sizeof(linger));
|
||||
@ -269,7 +276,8 @@ void close_zero_linger (void *socket)
|
||||
assert (rc == 0);
|
||||
}
|
||||
|
||||
void setup_test_environment()
|
||||
void
|
||||
setup_test_environment (void)
|
||||
{
|
||||
#if defined _WIN32
|
||||
# if defined _MSC_VER
|
||||
@ -296,8 +304,11 @@ void setup_test_environment()
|
||||
}
|
||||
|
||||
// Provide portable millisecond sleep
|
||||
// http://www.cplusplus.com/forum/unices/60161/ http://en.cppreference.com/w/cpp/thread/sleep_for
|
||||
void msleep (int milliseconds)
|
||||
// http://www.cplusplus.com/forum/unices/60161/
|
||||
// http://en.cppreference.com/w/cpp/thread/sleep_for
|
||||
|
||||
void
|
||||
msleep (int milliseconds)
|
||||
{
|
||||
#ifdef ZMQ_HAVE_WINDOWS
|
||||
Sleep (milliseconds);
|
||||
|
Loading…
x
Reference in New Issue
Block a user