How to response http request from eventbus consumer - java

Changed:
How to response http request from socket.
Web code:
public void start() {
Router router = Router.router(vertx);
router.route("/api/getdata").handler(this::getData);
vertx.createHttpServer().requestHandler(router::accept).listen(8080);
}
private void getData(RoutingContext routingContext) {
vertx.eventBus().send(ServerVerticle.ADDRESS, pricemessage, reply -> {
});
}
Socket code:
public void start() {
final EventBus eb = vertx.eventBus();
NetClient netClient = vertx.createNetClient();
if (ar.succeeded()) {
socket.handler(this::onDataReceived);
eb.consumer(ServerVerticle.ADDRESS, message -> {
socket.write(buffer); // request from the getData method
message.reply(data);// no data here, it's in the handler
}
}
}
private void onDataReceived(Buffer buffer) {
// buffer changed to JsonObject here
vertx.eventBus().send("some address here", jsonObject);
}
The socket handler has no return value. Just a eventbus send.
And I don't know how to response this jsonObject to the http request.
========================================================================
Old question, maybe not clear.
I have a vertex that handles the socket write and response.
public void start() { // 1
NetClient netClient = vertx.createNetClient();
netClient.connect(port, host, ar -> {
socket = ar.result(); // NetSocket
socket.handler(this::doSocketHandleMethod);
socket.write(BYTEBUFFER);// buffer here
})
}
private void doSocketHandleMethod(Buffer buffer){ // socket handler
// process data here and send
vertx.eventBus().send(ADDRESS, data here);
}
I use the below code to fetch the response from the http request.
public void start() {
Router router = Router.router(vertx);
router.route(API_GET).handler(this::getData);
vertx.eventBus().consumer(ADDRESSHERE, msg -> {
// get data from the socket send. 2
});
vertx.createHttpServer().requestHandler(router::accept).listen(8080, result -> {
});
}
private void getData(RoutingContext routingContext) {
vertx.eventBus().send(ADDRESS, message); // send message to the top // 1 verticle
// 3
}
The question is that the second code mention above gets the the data, but not sure how to fetch the response from the http reqest 3.

The (HttpServerRequest) is passed to the route (requestHandler(router::accept)) and is contained in the RoutingContext. "As HTTP requests are received by the server, instances of [...].HttpServerRequest will be created and passed to this handler." - JavaDoc
So, if the data arrives at 2 and you want to do a response to a HttpServerRequest (as a third step), you can use routingContext.response() in the getData() method, to get a HttpServerResponse.
If you want to handle a http server request, by sending a message to a consumer that is getting some data from a socket and want to send this result as a reply to the specific http server request, then you may do something like this:
// Send a message and get the response via handler
private void getData(RoutingContext routingContext) {
vertx.eventBus().send(ADDRESS, message, handler -> {
if(handler.succeded()) {
routingContext.response().end(handler.result());
}
else {
// error
}
});
}
// To reply to a message do
vertx.eventBus().consumer(ADDRESSHERE, msg -> {
// get data from the socket send. 2
msg.reply(data); // you can only do a reply once. Put data into reply
});
As far as I know, the event bus only knows "send and reply" and not a concept like a socket. It looks like you want to send data everytime new data is available through the socket.
You can write something to a httpResponse mutliple times, so you need to save a reference to the response object.
But I do not know, if that is such a good idea. I would recommend to encapsulate the socket-get-data process. The "socket" verticle only answers once, with the whole buffer it got. Here are two examples on what I mean.
// open socket
vertx.eventBus().consumer("ADRRESS", message -> {
// execute this on worker thread to not block the event bus thread
vertx.executeBlocking(future -> {
Buffer buffer = Buffer.buffer();
socket.handler(buff -> buffer.appendBuffer(buff)) // read data
.endHandler(endHandler -> {
// no more data to read
socket.pause();
future.complete(buffer);
})
.resume() // socket was paused, now read the data
.exceptionHandler(err -> future.fail(err)); // handle exception
}, result -> {
if(result.succeeded()) {
message.reply(result.result()); // reply with the buffer content
}
else {
message.reply(result.cause()); // may want to send error later
}
});
});
// connect and get a new socket every time
vertx.eventBus().consumer("ADRRESS", message -> {
// execute this on worker thread to not block the event bus thread
vertx.executeBlocking(future -> {
netClient.connect(1, "", netSocketHandler -> {
if(netSocketHandler.succeeded()) {
Buffer buffer = Buffer.buffer();
netSocketHandler.result().handler(buff -> buffer.appendBuffer(buff)) // read data
.endHandler(endHandler -> {
// no more data to read
future.complete(buffer);
netSocketHandler.result().close(); // close the NetSocket once finished
})
.exceptionHandler(err -> {
netSocketHandler.result().close();
future.fail(err);
}); // handle exceptions
}
else {
future.fail(netSocketHandler.cause());
}
});
}, result -> {
if(result.succeeded()) {
message.reply(result.result()); // reply with the buffer content
}
else {
message.reply(result.cause()); // may want to send error later
}
});
});
If this realy does not help you, I'm sorry, and maybe this is not the concept you are looking for.

Related

Netty 4 - The pool returns a channel which is not yet ready to send the the actual message

I have created an inbound handler of type SimpleChannelInboundHandler and added to pipeline. My intention is every time a connection is established, I wanted to send an application message called session open message and make the connection ready to send the actual message. To achieve this, the above inbound handler
over rides channelActive() where session open message is sent, In response to that I would get a session open confirmation message. Only after that I should be able to send any number of actual business message. I am using FixedChannelPool and initialised as follows. This works well some time on startup. But if the remote host closes the connection, after that if a message is sent calling the below sendMessage(), the message is sent even before the session open message through channelActive() and its response is obtained. So the server ignores the message as the session is not open yet when the business message was sent.
What I am looking for is, the pool should return only those channel that has called channelActive() event which has already sent the session open message and it has got its session open confirmation message from the server. How to deal with this situation?
public class SessionHandler extends SimpleChannelInboundHandler<byte[]> {
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
if (ctx.channel().isWritable()) {
ctx.channel().writeAndFlush("open session message".getBytes()).;
}
}
}
// At the time of loading the applicaiton
public void init() {
final Bootstrap bootStrap = new Bootstrap();
bootStrap.group(group).channel(NioSocketChannel.class).remoteAddress(hostname, port);
fixedPool = new FixedChannelPool(bootStrap, getChannelHandler(), 5);
// This is done to intialise connection and the channelActive() from above handler is invoked to keep the session open on startup
for (int i = 0; i < config.getMaxConnections(); i++) {
fixedPool.acquire().addListener(new FutureListener<Channel>() {
#Override
public void operationComplete(Future<Channel> future) throws Exception {
if (future.isSuccess()) {
} else {
LOGGER.error(" Channel initialzation failed...>>", future.cause());
}
}
});
}
}
//To actually send the message following method is invoked by the application.
public void sendMessage(final String businessMessage) {
fixedPool.acquire().addListener(new FutureListener<Channel>() {
#Override
public void operationComplete(Future<Channel> future) throws Exception {
if (future.isSuccess()) {
Channel channel = future.get();
if (channel.isOpen() && channel.isActive() && channel.isWritable()) {
channel.writeAndFlush(businessMessage).addListener(new GenericFutureListener<ChannelFuture>() {
#Override
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// success msg
} else {
// failure msg
}
}
});
fixedPool.release(channel);
}
} else {
// Failure
}
}
});
}
If there is no specific reason that you need to use a FixedChannelPool then you can use another data structure (List/Map) to store the Channels. You can add a channel to the data structure after sending open session message and remove it in the channelInactive method.
If you need to perform bulk operations on channels you can use a ChannelGroup for the purpose.
If you still want you use the FixedChannelPool you may set an attribute in the channel on whether open message was sent:
ctx.channel().attr(OPEN_MESSAGE_SENT).set(true);
you can get the attribute as follows in your sendMessage function:
boolean sent = ctx.channel().attr(OPEN_MESSAGE_SENT).get();
and in the channelInactive you may set the same to false or remove it.
Note OPEN_MESSAGE_SENT is an AttributeKey:
public static final AttributeKey<Boolean> OPEN_MESSAGE_SENT = AttributeKey.valueOf("OPEN_MESSAGE_SENT");
I know this is a rather old question, but I stumbled across the similar issue, not quite the same, but my issue was the ChannelInitializer in the Bootstrap.handler was never called.
The solution was to add the pipeline handlers to the pool handler's channelCreated method.
Here is my pool definition code that works now:
pool = new FixedChannelPool(httpBootstrap, new ChannelPoolHandler() {
#Override
public void channelCreated(Channel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(HTTP_CODEC, new HttpClientCodec());
pipeline.addLast(HTTP_HANDLER, new NettyHttpClientHandler());
}
#Override
public void channelAcquired(Channel ch) {
// NOOP
}
#Override
public void channelReleased(Channel ch) {
// NOOP
}
}, 10);
So in the getChannelHandler() method I assume you're creating a ChannelPoolHandler in its channelCreated method you could send your session message (ch.writeAndFlush("open session message".getBytes());) assuming you only need to send the session message once when a connection is created, else you if you need to send the session message every time you could add it to the channelAcquired method.

Netty Nio read the upcoming messages from ChannelFuture in Java

I am trying to use the following code which is an implementation of web sockets in Netty Nio. I have implment a JavaFx Gui and from the Gui I want to read the messages that are received from the Server or from other clients. The NettyClient code is like the following:
public static ChannelFuture callBack () throws Exception{
String host = "localhost";
int port = 8080;
try {
Bootstrap b = new Bootstrap();
b.group(workerGroup);
b.channel(NioSocketChannel.class);
b.option(ChannelOption.SO_KEEPALIVE, true);
b.handler(new ChannelInitializer<SocketChannel>() {
#Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new RequestDataEncoder(), new ResponseDataDecoder(),
new ClientHandler(i -> {
synchronized (lock) {
connectedClients = i;
lock.notifyAll();
}
}));
}
});
ChannelFuture f = b.connect(host, port).sync();
//f.channel().closeFuture().sync();
return f;
}
finally {
//workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) throws Exception {
ChannelFuture ret;
ClientHandler obj = new ClientHandler(i -> {
synchronized (lock) {
connectedClients = i;
lock.notifyAll();
}
});
ret = callBack();
int connected = connectedClients;
if (connected != 2) {
System.out.println("The number if the connected clients is not two before locking");
synchronized (lock) {
while (true) {
connected = connectedClients;
if (connected == 2)
break;
System.out.println("The number if the connected clients is not two");
lock.wait();
}
}
}
System.out.println("The number if the connected clients is two: " + connected );
ret.channel().read(); // can I use that from other parts of the code in order to read the incoming messages?
}
How can I use the returned channelFuture from the callBack from other parts of my code in order to read the incoming messages? Do I need to call again callBack, or how can I received the updated message of the channel? Could I possible use from my code (inside a button event) something like ret.channel().read() (so as to take the last message)?
By reading that code,the NettyClient is used to create connection(ClientHandler ),once connect done,ClientHandler.channelActive is called by Netty,if you want send data to server,you should put some code here. if this connection get message form server, ClientHandler.channelRead is called by Netty, put your code to handle message.
You also need to read doc to know how netty encoder/decoder works.
How can I use the returned channelFuture from the callBack from other parts of my code in order to read the incoming messages?
share those ClientHandler created by NettyClient(NettyClient.java line 29)
Do I need to call again callBack, or how can I received the updated message of the channel?
if server message come,ClientHandler.channelRead is called.
Could I possible use from my code (inside a button event) something like ret.channel().read() (so as to take the last message)?
yes you could,but not a netty way,to play with netty,you write callbacks(when message come,when message sent ...),wait netty call your code,that is : the driver is netty,not you.
last,do you really need such a heavy library to do network?if not ,try This code,it simple,easy to understanding

Android: Implementing a synchronous/blocking API using Messengers for IPC

I have a background service that runs in its own separate process using
android:process=":deamon"
In the manifest entry for the service. I want to communicate with the the service (remote process) from my activity and receive data from it.
I'm doing that by sending messages to and from the remote process as described in http://developer.android.com/guide/components/bound-services.html#Messenger and as they suggested I followed
If you want the service to respond, then you need to also create a Messenger in the client. >Then when the client receives the onServiceConnected() callback, it sends a Message to the >service that includes the client's Messenger in the replyTo parameter of the send() method.
The thing is, I need to provide a blocking/synchronous API to get data from my remote service, how can my "get" function block the caller and then return the data received in my incoming Handler ?
What would be the best approach to do that ?
This is code for messaging part of Client
SparseArray<CountDownLatch> lockArray = new SparseArray<>();
SparseArray<Bundle> msgDataArray = new SparseArray<>();
public Bundle sendAndWaitResponse(Message msg) throws
RemoteException, InterruptedException {
int msgId = msg.arg2;
Log.d("PlatformConnector", "Sending message to service, Type: "
+ msg.what + ", msgId: " + msg.arg2);
CountDownLatch latch = new CountDownLatch(1);
lockArray.put(msgId, latch);
platformMessenger.send(msg);
latch.await();
Bundle response = msgDataArray.get(msgId);
lockArray.delete(msgId);
msgDataArray.delete(msgId);
return response;
}
void storeResponseAndNotify(Message msg) {
int msgId = msg.arg2;
// Because the message itself is recycled after Handler returns,
// we should store only the data of message
msgDataArray.put(msgId, msg.getData());
lockArray.get(msgId).countDown();
}
private class ClientMessageHandler extends Handler {
#Override
public void handleMessage(Message msg) {
storeResponseAndNotify(msg);
}
}
This is example of utilizing above code.
RandomInt.getNextInt() is my custom static method, which generates random integer with Random.nextInt().
public JSONObject doSomething(JSONObject object) {
Message msg = Message.obtain(null, Constants.MESSAGE_SOMETHING, 0, RandomInt.getNextInt());
Bundle bundle = new Bundle();
bundle.putString(Constants.MESSAGE_DATA_SOMETHING, object.toString());
msg.setData(bundle);
try {
Bundle responseData = sendAndWaitResponse(msg);
return new JSONObject(responseData.getString(Constants.MESSAGE_DATA_RETURN));
} catch (RemoteException e) {
Log.e(TAG, "Failed to send message to platform");
e.printStackTrace();
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted while waiting message from platform");
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
Sequence is as follows,
The Client prepares Message and set its arg2 as some random integer
(this integer will be the message id for synchronization).
The Client prepares new CountDownLatch and put it to LockArray.
the Client sends message with sendAndWaitResponse(). It sends message to service via Messenger and invokes latch.await().
Service processes receives message and prepare reply message. The arg2 of this reply message should be same as received message.
Service sends reply message to client via Messenger in replyTo.
Client message handler handles the message with storeResponseAndNotify.
When the blocking of Client thread is finished, the response data would be already prepared in msgDataArray.
CountDownLatch is simple switch to block and unblock the thread.
(http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)
SparseArray is similar to HashMap, but more memory-efficient for smaller sets.
(http://developer.android.com/reference/android/util/SparseArray.html)
Be careful not to block the thread of Messenger. Messenger runs in single thread and if you block from the handleMessage(), it will block all other messages and cause deaklock problem.

Java Kryonet servers, client not receiving server response

I am trying to teach myself some networking in Java using the Kryonet library. The following code is almost identical to the code in the kyronet tutorial. https://code.google.com/p/kryonet/#Running_a_server
The client is successfully sending the message "Here is the request!" to the server (the server is printing it out) however the client is not receiving any response from the server even though the server is sending one.
I've tried unsuccessfully to fix it, can anyone see or suggest a possible problem/solution with the code?
(The code follows)
Client
public class Client_test {
Client client = new Client();
public Client_test() {
Kryo kryo = client.getKryo();
kryo.register(SomeRequest.class);
kryo.register(SomeResponse.class);
client.start();
try {
client.connect(50000, "127.0.0.1", 54555, 54777);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
client.addListener(new Listener() {
public void received (Connection connection, Object object) {
if (object instanceof SomeResponse) {
SomeResponse response = (SomeResponse)object;
System.out.println(response.text);
}
}
});
SomeRequest request = new SomeRequest();
request.text = "Here is the request!";
client.sendTCP(request);
}
}
Server
public class ServerGame {
Server server = new Server();
public ServerGame() {
Kryo kryo = server.getKryo();
kryo.register(SomeRequest.class);
kryo.register(SomeResponse.class);
server.start();
try {
server.bind(54555, 54777);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
server.addListener(new Listener() {
public void received (Connection connection, Object object) {
if (object instanceof SomeRequest) {
SomeRequest request = (SomeRequest)object;
System.out.println(request.text);
SomeResponse response = new SomeResponse();
response.text = "Thanks!";
connection.sendTCP(response);
}
}
});
}
}
Response & Request classes
public class SomeRequest {
public String text;
public SomeRequest(){}
}
public class SomeResponse {
public String text;
public SomeResponse(){}
}
After many hours watching youtube videos and sifting through the web I found the answer. Which I will post on here as it seems that quite a few people have had this problem so I would like to spread the word.
Basically the client would shut down immediately, before it could receive and output the message packet. This is because "Starting with r122, client update threads were made into daemon threads, causing the child processes to close as soon as they finish initializing.", the solution is "Maybe you could use this? new Thread(client).start();".
So basically instead of using
client.start();
to start the client thread you must use
new Thread(client).start();
Which I believe stops the thread being made into a daemon thread which therefore stops the problem.
Source: https://groups.google.com/forum/?fromgroups#!topic/kryonet-users/QTHiVmqljgE
Yes, inject a tool like Fiddler in between the two so you can see the traffic going back and forth. It's always easier to debug with greater transparency, more information.

JAVA server and .Net client programming

I am doing communication with Java server.
One application which is developed in java and it runs on some ip,port.
e.g. 192.168.1.1 port 9090
No wi want to communicate to that server using my ASp .NET ( C# )
I have following scenario:
connection with server
once the data has been trasferred, i have to inform the server that my data transfer is complete. So after that the server will process the data and will revert me(respone).
Then i will have to read that data.
When i am using the NetworkStream class.
I have 1 method which i am using is write to send data.
But the server dont understand the complete data has been received or not.
So it continuously wait for the data.
So how to do this?
Maybe you could consider to use Eneter Messaging Framework for that communication.
It is the lightweight cross-platform framework for the interprocess communication.
The Java service code would look something like this:
// Declare your type of request message.
public static class MyRequestMsg
{
public double Number1;
public double Number2;
}
// Declare your type of response message.
public static class MyResponseMsg
{
public double Result;
}
public static void main(String[] args) throws Exception
{
// Create receiver that receives MyRequestMsg and
// responses MyResponseMsg
IDuplexTypedMessagesFactory aReceiverFactory = new DuplexTypedMessagesFactory();
myReceiver =
aReceiverFactory.createDuplexTypedMessageReceiver(MyResponseMsg.class, MyRequestMsg.class);
// Subscribe to handle incoming messages.
myReceiver.messageReceived().subscribe(myOnMessageReceived);
// Create input channel listening to TCP.
IMessagingSystemFactory aMessaging = new TcpMessagingSystemFactory();
IDuplexInputChannel anInputChannel =
aMessaging.createDuplexInputChannel("tcp://127.0.0.1:4502/");
// Attach the input channel to the receiver and start the listening.
myReceiver.attachDuplexInputChannel(anInputChannel);
System.out.println("Java service is running. Press ENTER to stop.");
new BufferedReader(new InputStreamReader(System.in)).readLine();
// Detach the duplex input channel and stop the listening.
// Note: it releases the thread listening to messages.
myReceiver.detachDuplexInputChannel();
}
private static void onMessageReceived(Object sender,
TypedRequestReceivedEventArgs<MyRequestMsg> e)
{
// Get the request message.
MyRequest aRequest = e.getRequestMessage();
... process the request ...
// Response back the result.
MyResponseMsg aResponseMsg = new MyResponseMsg();
... set the result in the response message ...
try
{
// Send the response message.
myReceiver.sendResponseMessage(e.getResponseReceiverId(), aResponseMsg);
}
catch (Exception err)
{
EneterTrace.error("Sending the response message failed.", err);
}
}
// Handler used to subscribe for incoming messages.
private static EventHandler<TypedRequestReceivedEventArgs<MyRequestMsg>> myOnMessageReceived
= new EventHandler<TypedRequestReceivedEventArgs<MyRequestMsg>>()
{
#Override
public void onEvent(Object sender, TypedRequestReceivedEventArgs<MyRequestMsg> e)
{
onMessageReceived(sender, e);
}
};
And the .NET client would look something like this:
public class MyRequestMsg
{
public double Number1 { get; set; }
public double Number2 { get; set; }
}
public class MyResponseMsg
{
public double Result { get; set; }
}
private IDuplexTypedMessageSender<MyResponseMsg, MyRequestMsg> myMessageSender;
private void OpenConnection()
{
// Create message sender.
// It sends string and as a response receives also string.
IDuplexTypedMessagesFactory aTypedMessagesFactory = new DuplexTypedMessagesFactory();
myMessageSender =
aTypedMessagesFactory.CreateDuplexTypedMessageSender<MyResponseMsg, MyRequestMsg>();
// Subscribe to receive response messages.
myMessageSender.ResponseReceived += OnResponseReceived;
// Create TCP messaging.
IMessagingSystemFactory aMessaging = new TcpMessagingSystemFactory();
IDuplexOutputChannel anOutputChannel =
aMessaging.CreateDuplexOutputChannel("tcp://127.0.0.1:4502/");
// Attach the output channel to the message sender and be able
// send messages and receive responses.
myMessageSender.AttachDuplexOutputChannel(anOutputChannel);
}
private void CloseConnection(object sender, FormClosedEventArgs e)
{
// Detach output channel and stop listening to response messages.
myMessageSender.DetachDuplexOutputChannel();
}
private void SendMessage()
{
// Create message.
MyRequestMsg aRequestMessage = new MyRequestMsg();
...
// Send message.
myMessageSender.SendRequestMessage(aRequestMessage);
}
private void OnResponseReceived(object sender,
TypedResponseReceivedEventArgs<MyResponseMsg> e)
{
// Get the response message.
MyResponseMsg aResponse = e.ResponseMessage;
.... process the response from your Java client ....
}

Categories