C ZeroMQ zstr_recv hangs - c

I have two simple programs: a client and a server. I'm trying to use zstr_sendfm and zstr_recv to send and receive a simple string. Roughly speaking, I'm using the code from the file transfer test in the zeromq tutorial. Here's the server function:
#define PIPELINE = 10;
int server()
{
char *name = "someName";
zctx_t *ctx = zctx_new();
void *router = zsocket_new(ctx, ZMQ_ROUTER);
zsocket_set_hwm(router, PIPELINE*2);
if (0 == zsocket_connect(router, tcp://127.0.0.1:6000))
{
printf("failed to connect to router.\n");
}
printf( "sending name %s\n, name);
zstr_sendfm( router, name );
return 0;
}
Here's the client function:
int client()
{
zctx_t *ctx = zctx_new ();
void *dealer = zsocket_new (ctx, ZMQ_DEALER);
zsocket_bind(dealer, "tcp://*:6000")
char *receivedName = zstr_recv( dealer );
printf("received the following name: %s\n", receivedName);
return 0
}
Both of these are run in two separate programs (which do nothing other than run their respective functions) on the same computer.
Here's how things always play out:
Start client function, which holds at "zstr_recv" as it's supposed to
Start server function, which connects successfully, claims to have sent the data, and exits
Client function continues to sit and wait, but claims to have not received anything from the server.
What am I missing here? I've added a bunch of error checking and even tried this out in gdb with no luck.
Help and advice appreciated.

I think you have your client and server mixed up, although in ZeroMQ client and server is not as strict as with normal sockets. Normally you would create a server with a REP socket that binds/receives/sends and a client with a REQ socket that connects/sends/receives. You should try this first and then experiment with ROUTER for the server (instead of REP) and DEALER for the client (instead of REQ).

Related

How to connect to zookeeper server from different machine?

My code, which is written in C for the C Client binding for zookeeper, runs perfectly on my local computer using the same ip (not localhost:2181). However, compiling and executing my code on another computer yields with a connection loss error. I was not able to connect to my zookeeper server by using my public IP(I got my publicIP by looking up whatsmyip on google). I did an ifconfig on my terminal to get the 10.111.129.199. I am assuming this is a private IP as it starts with 10. The machine I have ssh'd to is running SolarisOS. This caused me to change a single function in zookeeper source code from synch_fetch_and_add (I think) to atomic_add because sync_fetch... is not supported by SolarisOS. According to ZooKeeper documentation, SolarisOS is not currently supported by Zookeeper. I am able to compile Zookeeper perfectly fine, and am told someone else in my company had implemented Zookeeper beforehand on our systems.
My program is trying to create a single node on the zookeeper server. My code looks like this:
int main(int argc, char *argv[]){
//zh is a global zookeeper_handle for now.
zh = zookeeper_init(host_port, my_watcher_func, 20000, 0, NULL, 0);
if(zh == NULL){
fprintf(stderr, "Error connecting to ZooKeeper Server!! \n");
exit(EXIT_FAILURE);
return 0;
}
int retval = create("/TFS/pool" , "1");
printf("return value of create = %d\n", retval);
}
int create(char* path, char* data){
int value_length= -1;
if(data != NULL){
value_length = (int) strlen(data);
}
printf("creating node at path: %s with data %s\n", path, data);
int retval = zoo_create( zh, path, data, value_length,
&ZOO_OPEN_ACL_UNSAFE, 0, 0, 0);
return retval;
}
/*empty watcher function*/
//I have no idea why this is needed.
void my_watcher_func(zhandle_t *zzh, int type, int state,
const char *path, void *watcherCtx) {}
Both systems are running GCC compiler. The problem, I think, isn't in the code as it runs fine locally, but the connection issue I am facing.
I would assume that zh would return 0 if the connection to the zookeeper was a failure from the zookeeper_init() function. This however does not happen and continues to the create().
creating node at path: /TFS/pool with data abc
2018-07-16
10:30:44,232:16332(0x2):ZOO_ERROR#handle_socket_error_msg#1670: Socket
[10.111.129.190:2181] zk retcode=-4, errno=0(Error 0): connect() call
failed
return value of create = -4
When I telnet to the ip:port it will connect. I also know that zookeeper detects my connection during telnet because I am running it in the foreground. The following is the output of zkServer.sh running in foreground when I connect via telnet 10.111.129.190 2181
2018-07-16 11:04:03,807 [myid:] - INFO
[NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory#215] -
Accepted socket connection from /10.7.1.70:61479
The expected output should have been:
creating node at path: /TFS/pool with data 1
2018-07-16 12:14:37,078:3180(0x70000c98c000):ZOO_INFO#check_events#1764: initiated connection to server [10.111.129.190:10101]
2018-07-16 12:14:37,107:3180(0x70000c98c000):ZOO_INFO#check_events#1811: session establishment complete on server [10.111.129.190:10101], sessionId=0x10000590d2b0000, negotiated timeout=20000
return value of create = 0
This output has always confused me as zookeeper connection is established after the zookeeper_handle is initiated. It is established upon zoo_create() instead of zookeeper_init. Doesn't effect anything, but just an interesting time to establish a connection.
I understand that retcode=-4 means CONNECTIONLOSS, but it's not even able to establish a connection with the server. If there is anyway I could fix this please do tell!.

Node.js ZeroMQ client does not exchange REQ/REP messages with a C ZeroMQ server

Using the examples provided by the ZeroMQ docs, I cannot get them work with a server written in C and a node.js client.
The examples I use are:
http://zguide.zeromq.org/js:rrclient
for Node.js:
// Hello World client in Node.js
// Connects REQ socket to tcp://localhost:5559
// Sends "Hello" to server, expects "World" back
var zmq = require('zmq')
, requester = zmq.socket('req');
requester.connect('tcp://localhost:5560');
var replyNbr = 0;
requester.on('message', function(msg) {
console.log('got reply', replyNbr, msg.toString());
replyNbr += 1;
});
for (var i = 0; i < 10; ++i) {
requester.send("Hello");
}
and
https://github.com/booksbyus/zguide/blob/master/examples/C/rrworker.c
for the C server:
// Hello World worker
// Connects REP socket to tcp://localhost:5560
// Expects "Hello" from client, replies with "World"
#include "zhelpers.h"
#include <unistd.h>
int main (void)
{
void *context = zmq_ctx_new ();
// Socket to talk to clients
void *responder = zmq_socket (context, ZMQ_REP);
//zmq_connect (responder, "tcp://localhost:5560");
// using bind instead of connect
zmq_bind (responder, "tcp://localhost:5560");
while (1) {
// Wait for next request from client
char *string = s_recv (responder);
printf ("Received request: [%s]\n", string);
free (string);
// Do some 'work'
sleep (1);
// Send reply back to client
s_send (responder, "World");
}
// We never get here, but clean up anyhow
zmq_close (responder);
zmq_ctx_destroy (context);
return 0;
}
I changed the port, so they now match ( 5560 ). However I get no data transmitted. Neither the client nor the server gets any message.
Why? Simply they both just remained listening
Where?
requester.connect(..) // in Node.js copy/paste code
resp.
zmq_connect ( responder, "tcp://localhost:5560" ); // in C copy/paste code
The logic of a ZeroMQ signalling / messaging infrastructure is a bit more complex.
One side of the REQ/REP has to .bind() and all the others may try to .connect().
This is valid in principle, applicable to all ZeroMQ Scalable Formal Communication Pattern archetypes, not just to the REQ/REP one.
So, in this use-case,
either side -- be it a Node.js or the C -- may start with the .bind()
and
the other one will be able to try to .connect() to such a .bind()-prepared and ready IP:port# target.
..
int rc = zmq_bind( responder, "tcp://localhost:5560" );
/* zmq_bind()
returns:
* zero if successful.
* -1 otherwise
and
sets errno to one of the values
as defined in API.
*/
..
There are many good practices to follow in ZeroMQ domain. Registering and handling the return codes from the function calls being one such topic in ZeroMQ best practices. Do not hesitate to learn faster and read through many man*years of a Collective-Experience in this here.
Binding to localhost does not seem to work, so I tried 127.0.0.1 and it works.

Block a client without blocking others in Select

I have to create a program with two parts : Client / Server.
I receive commands from different clients and I want to put the client waiting during the command is executed, but, the other clients must be able to send command to the server
e.g :
C1 (for client 1) and C2 (for client 2)
C1 send command -> server receive it and execute it and he can't accept command from C1 for x seconds but he can accept command from the C2.
How can I do it with select function withous threads.
This is my current code from the server :
void client_ask(t_listplayer *list, t_network *net) {
char *buffer = xmalloc(sizeof(char) * 200);
int rd = 0;
memset(buffer, 0, 200);
while (list != NULL) {
if (FD_ISSET(list->player->fd, &net->readfds)) {
if ((rd = xread(list->player->fd, buffer, 200)) > 0) {
buffer[rd - 1] = '\0';
printf("Client n°: %d asking : [%s]\n", list->player->fd, buffer);
sleep(3); // This one put all the server in waiting
memset(buffer, 0, 200);
} else {
close(list->player->fd);
printf("Client n°: %d has just disconnected", list->player->fd);
}
}
list = list->next;
}
}
So, I've make many research .. I've heard things about timeout but i don't know how to do this.
Thanks
You could manage client-states in your list of clients. If the client state is 'wait', do not answer it (or better : answer "you must wait for x" or some useful feedback). All the clients will be able to send requests and only the one in the correct states will be processed.
Do not forget to reset the client's state when your work is done on its request.

Message passing with czmq

I'm trying to use czmq, the first test was ok with the inproc protocol and if the "puller" and the "pusher" in the same program.
But I want to use it on different processus, I also tried ipc and tcp, and I can not achieve to make communicate the server and the client.
The server:
#include <czmq.h>
int main (void)
{
zctx_t *ctx = zctx_new ();
void *reader = zsocket_new (ctx, ZMQ_PULL);
int rc = zsocket_connect (reader, "tcp://localhost:5555");
printf("wait for a message...\n");
char *message = zstr_recv (reader);
printf("Message: %s",message);
zctx_destroy (&ctx);
return 0;
}
and the client:
#include <czmq.h>
int main (void)
{
zctx_t *ctx = zctx_new ();
void *writer = zsocket_new (ctx, ZMQ_PUSH);
int rc = zsocket_bind (writer, "tcp://*:5555");
assert (rc == service);
zstr_send (writer, "HELLO");
zsocket_destroy (ctx, writer);
return 0;
}
Could you tell me what is wrong with my code. I have also tried other sample codes found, but without more success.
Update
The server is waiting for messages in zstr_recv, but the messages send by the client triggers nothing on the server process.
After sending the message, the client process is destroying the socket too quickly. With inproc, you "get away with it" because inproc is fast, while TCP has to go through more hurdles before the message gets to the TCP stack.
It is true that zsocket_destroy() should block until the message is sent, if ZMQ_LINGER = -1 (the default with raw ZMQ), but the default linger for CZMQ is 0. That means dropping in-transit messages when the socket is destroyed.
Try setting the linger (with zctx_set_linger) to something bigger than zero; 10ms perhaps, but use whatever value is good for you.

queueing recv in server connection

The situation: I am creating a server daemon in c that accepts numerous simultaneous connections, and the clients will be sending data to the server. I currently have each client connection being spawned into a new thread.
The problem: if a client sends numerous lines of content very quickly (eg, 10 lines of data in less than a second), the server will see the first two lines, but not the rest.
The question: How can I "queue" the data coming in from the clients (the recv command in c)? Is this something that select or poll would be needed for? Basically, I want to make sure any client can send large amounts of data very quickly without having to worry about any content being dropped. How can this be achieved?
Sample Code: (note: the below code has obviously been heavily modified, esp. by removing error checking. I tried to modify my code so as to make the problem/solution clear without getting bogged down in semantics of irrelevant parts. Please don't get caught up with any non-standard or missing elements here)
//this function handles the threads
void *ThreadedFunction(void *arg) {
// do some stuff, like: pull vars out of mystruct
int nbytes;
char buf[256];
while(1) {
if((nbytes=recv(conid, buf, sizeof buf, 0)) <= 0) {
//handle break in connection
} else {
//for this example, just print out data from client to make my point
buf[nbytes] = 0;
printf("%s\n",buf);
}
}
}
//main just sets up the connections and creates threads
int main(int argc. char *argv[])
{
// bind(), listen(), etc... blah blah blah
while(1) {
conid = accept(...); //get a connection
// ... build mystruct to pass vars to threaded function ...
pthread_t p;
pthread_create(&p,NULL,ThreadedFunction,&mystruct); //create new thread
}
}
You don't need to "queue" the data coming in from the clients.
Because TCP do that for you. Flow control of TCP even slows down clients, if the server is too slow to make space to TCP receiving buffer.
So, probably there is bug in the code of server or client. Maybe client sends '\0' in the end of each line. In that case, the following code would not print all lines:
if((nbytes=recv(conid, buf, sizeof buf, 0)) <= 0) {
//handle break in connection
} else {
//for this example, just print out data from client to make my point
buf[nbytes] = 0;
printf("%s\n",buf);
}
It is even expected that the 2nd line is the last line what you see, if client sends '\0' at the end of each line.
For example:
If client sends the following lines:
"abc\n\0"
"def\n\0"
"ghi\n\0"
TCP will usually send those by using two packets, that contains following:
"abc\n\0"
"def\n\0ghi\n\0"
Server usually needs 2 recv calls to receive the incoming data.
So your server will use 2 print calls:
printf("%s\n", "abc\n\0\0");
printf("%s\n", "def\n\0ghi\n\0\0");
And the result output is:
abc
def

Resources