I found some code on this link http://www.techbrainwave.com/?p=912 which describes how to set up a client server architecture using apache mina. However, in the example provided it is only one-way communication (from client to server). Does anyone know how to modify this in order to obtain two-way communication?
If you want the server to reply to the client message, you need to do it in the IoHandler of the server :
#Override
public void messageReceived(IoSession session, Object message)
{
logger.info("Message received in the server..");
logger.info("Message is: " + message.toString());
// reply to the client
session.write( /*the reply message here */);
}
Related
I have a gRPC service simmilar to below
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
I need the client to maintain a long living gRPC connection to the server so that if the server goes down, the client can reconnect and issue SayHello() again.
Based on my understanding there are a few options:
Pass in a statsHandler to grpc.Dial and add retry logic in HandleConn()
Add a new ClientStreaming API that maybe sends a message every few seconds. Check for server side stream close errors and implement retry logic.
Not sure if there is a recommended way for my use case and would appreciate any help.
How can I block netty to send ACK responese to client in netty 4.x ?
I'm trying to control TCP packet receive speed in netty in order to forward these packet to another server . Netty receive all client packets immediately ,but netty need more time send them out , so client think it finished after sending to netty .
So , I want to know how to block received packets when netty forwarding packets which are received before to another server .
Not sure to really understand your question. So I try to reformulate:
I suppose that your Netty server is acting as a Proxy between clients and another server.
I suppose that what you want to do is to send the ack back to the client only once you really send the forwarded packet to the final server (not necesseraly received by the final server, but at least send by Netty proxy).
If so, then you should use the future of the forwarded packet to respond back with the ack, such as (pseudo code):
channelOrCtxToFinalServer.writeAndFlush(packetToForward).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) {
// Perform Ack write back
ctxOfClientChannel.writeAndFlush(AckPacket);
}
});
where:
channelOrCtxToFinalServer is one of ChannelHandlerContext or Channel connected to your remote final server from your Netty proxy,
and ctxOfClientChannel is the current ChannelHandlerContext from your Netty handler that receive the packet from the client in public void channelRead(ChannelHandlerContext ctxOfClientChannel, Object packetToForward) method.
EDIT:
For the big file transfer issue, you can have a look at the Proxy example here.
In particular, pay attention on the following:
Using the same logic, pay attention on receiving data one by one from client:
yourServerBootstrap..childOption(ChannelOption.AUTO_READ, false);
// Allow to control one by one the speed of reception of client's packets
In your frontend handler:
public void channelRead(final ChannelHandlerContext ctx, Object msg) {
if (outboundChannel.isActive()) {
outboundChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
// was able to flush out data, start to read the next chunk
ctx.channel().read();
} else {
future.channel().close();
}
}
});
}
}
And finally add, using the very same logic, the final ack to your client (ack depending of course on your protocol): (see here and here)
/**
* Closes the specified channel after all queued write requests are flushed.
*/
static void closeOnFlush(Channel ch) {
if (ch.isActive()) {
ch.writeAndFlush(AckPacket).addListener(ChannelFutureListener.CLOSE);
}
}
I'm new to ZeroMQ (and to networking in general), and have a question about using ZeroMQ in a setup where multiple clients connect to a single server. My situation is as follows:
--1 server
--multiple clients
--Clients send messages to server: I've already figured out how to do this part.
--Server sends messages to a specific client: This is the part I'm having trouble with. When certain events get handled on the server, the server will need to send a message to a specific client -- not all clients. In other words, the server will need to be able to choose which client to send a given message to.
Right now, this is my server code:
using (NetMQContext ctx = NetMQContext.Create())
{
using (var server = ctx.CreateResponseSocket())
{
server.Bind(#"tcp://127.0.0.1:5555");
while (true)
{
string fromClientMessage = server.ReceiveString();
Console.WriteLine("From Client: {0}", fromClientMessage);
server.Send("ack"); // There is no overload for the 'Send'
method that takes an IP address as an argument!
}
}
}
I have a feeling that the problem is that my design is wrong, and that the ResponseSocket type isn't meant to be used in the way that I want to use it. Since I'm new to this, any advice is very much appreciated!
when using the Response socket you always replying to the client that sent you the message. So the Request-Response socket types together are just simple request response.
To more complicated scenarios you probably want to use Dealer-Router.
With router the first frame of each message is the routing id (the identity of the client that sent you the message)
so your example with router will look like:
using (NetMQContext ctx = NetMQContext.Create())
{
using (var server = ctx.CreateRouterSocket())
{
server.Bind(#"tcp://127.0.0.1:5555");
while (true)
{
byte[] routingId = server.Receive();
string fromClientMessage = server.ReceiveString();
Console.WriteLine("From Client: {0}", fromClientMessage);
server.SendMore(routingId).Send("ack");
}
}
}
I also suggest to read the zeromq guide, it will probably answer most of your questions.
I'm confused by a warning in the api of zmq_poll: "The zmq_send() function will clear all pending events on a socket. Thus, if you use zmq_poll() to monitor input on a socket, use it before output as well, and process all events after each zmq_poll() call."
I don't understand what that means. Since events are level-triggered. If I call zmq_send() and then zmq_poll(), any pending messages in the socket's buffer should trigger the zmq_poll again immediately. Why one needs to "use it (zmq_poll) before output as well" or "process all events after each zmq_poll() call"?
I see your point, the documentation is confusing. Here's a simple test in Java using a client-side DEALER socket with a poller (from asyncsrv) . The server sends 3 messages to the client. The client polls and outputs each message it receives. I've added send() in the client to test your theory. Assuming send() clears the poller, we expect the client to output receipt of only a single message:
Server
public static void main(String[] args) {
Context context = ZMQ.context(1);
ZMQ.Socket server = context.socket(ZMQ.ROUTER);
server.bind("tcp://*:5555");
server.sendMore("clientId");
server.send("msg1");
server.sendMore("clientId");
server.send("msg2");
server.sendMore("clientId");
server.send("msg3");
}
Client
public void run() {
socket = context.socket(ZMQ.DEALER);
socket.setIdentity("clientId".getBytes());
socket.connect("tcp://localhost:5555");
ZMQ.Poller poller = new ZMQ.Poller(1);
poller.register(socket, ZMQ.Poller.POLLIN);
while (true) {
poller.poll();
if (poller.pollin(0)) {
String msg = socket.recvStr(0);
System.out.println("Client got msg: " + msg);
socket.send("whatever", 0);
}
}
}
outputs...
Client got msg: msg1
Client got msg: msg2
Client got msg: msg3
Based on the results, doing send() does not clear the poller for socket, and it should be obvious why. We configured the poller with POLLIN, meaning the poller listens for inbound messages to socket. When doing socket.send(), it creates outbound messages, on which the poller is not listening.
Hope it helps...
I'm very new to ZeroMQ. I've read the guide and am currently going through the examples as well as looking at other relevant info around the web. I'm having some indecision with what message pattern(s) to use or if I should use a combination of 2 patterns.
I have an existing software application that has a home grown messaging system that is in need of replacement. I have a fairly simple architecture:
|Client|<----->|driver1|
|
|---|driverN|
Only one "client" connects to a driver at a time currently, and there may be many drivers.
(in actuality, the client, in this case, isn't truly my client application, but a middleman of sorts. For this discussion, it can be treated as a client)
Messaging:
The client issues commands to the driver.
The drivers return status/state information in response to commands.
The drivers produce data elements (i.e. Not status/state information)
Some Client messages go to all connected devices, some are directed only to a single driver.
Drivers may exist on the same system or remotely on a LAN. This is not a public network.
I'm currently thinking that I would have a pub and sub socket on each driver and a sub/pub socket on the client. Messages shouldn't be dropped once a connection is made. I assume that the client would subscribe to the different driver data types and the driver would then subscribe to the clients command messages.
Important considerations: low latency, lowest possible bandwidth overhead.
I would appreciate any suggestions or recommendations! Thanks in advance!
You picked a great learning exercise, that's for sure!
Read up on these, they provide the basic implementation for request/reply using a custom router-to-router proxy with polling and should address your client-to-device problem.
https://github.com/imatix/zguide/blob/master/examples/C/lbbroker.c
https://github.com/imatix/zguide/blob/master/examples/C/lbbroker2.c
The solution is synchronous, so any request sent from the client blocks until it gets a response. Personally I would use async for both request and reply for total flexibility, but that solution is way more complex. There are, however, examples in the book called Freelance and Dealer/Router that illustrate async request/reply.
Here's an example for synchronous many-to-many request/reply. You MUST know how ZeroMq enveloping works to fully understand the mechanics of this approach; see example lbbroker1.
Client
Set the client identity with setIdentity(); important for response routing.
Client sends requests for device1, device2, etc, in a loop; if device exists, status messages returned from specific device, otherwise, "no device" returned to client.
Socket client = context.socket(ZMQ.REQ);
client.setIdentity("client1".getBytes());
client.connect("tcp://localhost:5550");
for( int i = 0; i < 5; i++){
client.send("device" + i);
String reply = client.recvStr();
log("Received message: " + reply);
Thread.currentThread().sleep(1000);
}
Device
Device sets id just like client for unique routing.
Device sends device.send("DEVICEREADY") to server to signal online availability.
Device does recvStr() three times to read full envelope from server.
String deviceId = "device1"
Socket device = context.socket(ZMQ.REQ);
device.setIdentity(deviceId.getBytes());
device.connect( "tcp://localhost:5560");
device.send( "DEVICEREADY");
while (!Thread.currentThread().isInterrupted()) {
String clientAddress = device.recvStr();
String empty = device.recvStr();
String clientRequest = device.recvStr();
//create envelope to send reply to same client who made request
device.sendMore(clientAddress);
device.sendMore("");
device.send( "stauts on " + deviceId + " is ok");
}
Server (Router/Router)
A custom proxy using ROUTER sockets; clients connect to frontend ROUTER socket while devices connect to backend router. Server polls on both sockets for messages.
Context context = ZMQ.context(1);
Socket frontend = context.socket(ZMQ.ROUTER);
Socket backend = context.socket(ZMQ.ROUTER);
frontend.bind( "tcp://localhost:5550");
backend.bind( "tcp://localhost:5560");
Poller poller = new Poller(2);
poller.register(frontend, Poller.POLLIN);
poller.register(backend, Poller.POLLIN);
while (!Thread.currentThread().isInterrupted()) {
poller.poll();
//frontend poller
if (poller.pollin(0)) {
String clientId = frontend.recvStr();
String empty = frontend.recvStr(); //empty frame
String deviceId = frontend.recvStr();
//if client is requesting to talk to nonexistent deviceId,
//return message "no device", otherwise, create envelope and send
//request on backend router to device.
if( deviceMap.get( deviceId) == null ){
frontend.sendMore(clientId);
frontend.sendMore("");
frontend.send("no deviceId: " + deviceId);
} else {
//request envelope addressed to specific device
backend.sendMore(deviceId);
backend.sendMore("");
backend.sendMore(clientId);
backend.sendMore("");
backend.send("hello from " + clientId);
}
}
//backend poller
if(poller.pollin(1)){
String deviceId = backend.recvStr();
String empty = backend.recvStr();
String clientId = backend.recvStr();
//device signaling it's ready
//store deviceId in map, don't send a response
if( clientId.equals("DEVICEREADY"))
deviceMap.put(deviceId, deviceId);
else {
//the device is sending a response to a client
//create envelope addressed to client, send on frontend socket
empty = backend.recvStr();
String reply = backend.recvStr();
frontend.sendMore(clientId);
frontend.sendMore("");
frontend.send(reply);
}
}
}