How to read data immediantly from client? - java

How can i get data immediantly from client in server netty 4.
In moment when i sending data to client ,client send me data.But handler (method channelRead())received data only after server sended a data
The problem i will show in a process list, i use netty 4:
get data from client
start calculate response
send some service data to client as (ctx.writeAndFlush()) (ok)
continue calculate response
should get data from client (here a problem)
send calculated response to client(sends ok).
My Code:
Handler
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
logger.debug("Start read handler " + ctx.channel().toString());
ByteBuf b = (ByteBuf) msg;
ctx.write(Unpooled.copiedBuffer( new Test.send(ctx,b) );
}
Test
public class Test
public byte[] send(ChannelHandlerContext ctx,ByteBuf b){
// start calculates
ctx.writeAndFlush(Unpooled.copiedBuffer(some data)); - its ok
// calculates .. (during here i should get data from client but nothing happens. Why does the channel blocks receiving data ? )
return response;
}

You should have an ChannelInboundHandler which will be notified once the response was received. Remember everything in netty is non-blocking.

Related

How can I send more then one response to client from a Httpserver base on Netty

How can I send more then one response to client from a Httpserver base on Netty?
I am trying to make a httpserver by netty and it works.
Now I have a question,can I send more then one response to client from a Httpserver ?
For example, the client requests the server from a web browser, and server responses "hello" then responses "bye" several seconds later.
I add three handles:
sc.pipeline().addLast(new HttpResponseEncoder());
sc.pipeline().addLast(new HttpRequestDecoder());
sc.pipeline().addLast(new HttpChannelHandler());
In the HttpChannelHandler ,I tried to response twice,but failed
public class HttpChannelHandler extends ChannelInboundHandlerAdapter {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof HttpRequest) {
//the content response to the client
String resp_content = "hello";
request = (HttpRequest) msg;
boolean keepaLive = HttpHeaders.isKeepAlive(request);
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1,
OK, Unpooled.copiedBuffer(resp_content.getBytes("UTF-8")));
response.headers().set(CONTENT_TYPE, "text/html;charset=UTF-8");
response.headers().set(CONTENT_LENGTH,
response.content().readableBytes());
if (keepaLive) {
response.headers().set(CONNECTION, KEEP_ALIVE);
//first response
ctx.writeAndFlush(response);
content = "test";
response.headers().set(CONTENT_TYPE, "text/html;charset=UTF-8");
response.headers().set(CONTENT_LENGTH,
response.content().readableBytes());
//second response,but failed
// exception io.netty.util.IllegalReferenceCountException: refCnt: 0
response.content().writeBytes(resp_content.getBytes());
ctx.writeAndFlush(response);
}
}
}
}
No thats not possible... HTTP is a "request/response" style protocol. Once you sent a response to the client you can only send another one when you receive another request.

Vert.x how to pass/get messages from REST to message bus?

I want to pass messages to bus via REST, and get it back. But I cant correctly setup the message bus receiver, it throws java.lang.IllegalStateException: Response has already been written. In real life message bus should receive messages from different sources and pass a message to another target. Therefore we just need to publish the message to the bus. But how to correctly read messages and handle all of them? For example from a REST interface: read that messages!
My simple app start:
public static void main(String[] args) {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new RESTVerticle());
vertx.deployVerticle(new Receiver());
EventBus eventBus = vertx.eventBus();
eventBus.registerDefaultCodec(MessageDTO.class, new CustomMessageCodec());
}
REST part
public class RESTVerticle extends AbstractVerticle {
private EventBus eventBus = null;
#Override
public void start() throws Exception {
Router router = Router.router(vertx);
eventBus = vertx.eventBus();
router.route().handler(BodyHandler.create());
router.route().handler(CorsHandler.create("*")
.allowedMethod(HttpMethod.GET)
.allowedHeader("Content-Type"));
router.post("/api/message").handler(this::publishToEventBus);
// router.get("/api/messagelist").handler(this::getMessagesFromBus);
router.route("/*").handler(StaticHandler.create());
vertx.createHttpServer().requestHandler(router::accept).listen(9999);
System.out.println("Service running at 0.0.0.0:9999");
}
private void publishToEventBus(RoutingContext routingContext) {
System.out.println("routingContext.getBodyAsString() " + routingContext.getBodyAsString());
final MessageDTO message = Json.decodeValue(routingContext.getBodyAsString(),
MessageDTO.class);
HttpServerResponse response = routingContext.response();
response.setStatusCode(201)
.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily(message));
eventBus.publish("messagesBus", message);
}
And the Receiver: I move it to a different class, but it does not help
public class Receiver extends AbstractVerticle {
#Override
public void start() throws Exception {
EventBus eventBus = vertx.eventBus();
Router router = Router.router(vertx);
router.route().handler(BodyHandler.create());
router.route().handler(CorsHandler.create("*")
.allowedMethod(HttpMethod.GET)
.allowedHeader("Content-Type"));
router.get("/api/messagelist").handler(this::getMessagesFromBus);
router.route("/*").handler(StaticHandler.create());
vertx.createHttpServer().requestHandler(router::accept).listen(9998);
System.out.println("Service Receiver running at 0.0.0.0:9998");
private void getMessagesFromBus(RoutingContext routingContext) {
EventBus eventBus = vertx.eventBus();
eventBus.consumer("messagesBus", message -> {
MessageDTO customMessage = (MessageDTO) message.body();
HttpServerResponse response = routingContext.response();
System.out.println("Receiver ->>>>>>>> " + customMessage);
if (customMessage != null) {
response.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily(customMessage));
}
response.closed();
});
}
So if i post message to REST and handler publish it to the bus, when I am runtime get http://localhost:9998/api/messagelist it is return json, but second time it trow exception
java.lang.IllegalStateException: Response has already been written
at io.vertx.core.http.impl.HttpServerResponseImpl.checkWritten(HttpServerResponseImpl.java:561)
at io.vertx.core.http.impl.HttpServerResponseImpl.putHeader(HttpServerResponseImpl.java:154)
at io.vertx.core.http.impl.HttpServerResponseImpl.putHeader(HttpServerResponseImpl.java:52)
at com.project.backend.Receiver.lambda$getMessagesFromBus$0(Receiver.java:55)
at io.vertx.core.eventbus.impl.HandlerRegistration.handleMessage(HandlerRegistration.java:207)
at io.vertx.core.eventbus.impl.HandlerRegistration.handle(HandlerRegistration.java:201)
at io.vertx.core.eventbus.impl.EventBusImpl.lambda$deliverToHandler$127(EventBusImpl.java:498)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$18(ContextImpl.java:335)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:358)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
at java.lang.Thread.run(Thread.java:745)
Receiver ->>>>>>>> Message{username=Aaaewfewf2d, message=41414wefwef2d2}
How to correctly get all messages from the receiver? Or if the bus received messages, should I immediately store them to the db? Can a message bus keep messages and not lost them?
Thanks
Each hit in the entry point "/api/messagelist" creates one new consumer with the request routing context.
The first request will create the consumer and reply to the request. When the second message was published, that consumer will receive the message and will reply to the previous request (instance) and this was closed.
I think that you misunderstood the event bus purpose and I really recommend you to read the documentation.
http://vertx.io/docs/vertx-core/java/#event_bus
I did not had the chance to test your code but it seems that the publish operation is throwing an exception and vertx will try to send back an error message. However you already replied and ended the connection.
Now the error might be from your codec but due to the asynchronous nature of vertx you only see it at a later stage and mangled with the internal error handler.

Limit the number of transaction per seconds on HTTP persistent connection Using Netty (http client)

Is there any mechanism/api by which I can control TPS hits from http client?
From HTTP client, I need to control numbers of hits to rest services (my HTTP client will hit to server in controlled manner).
you can close it immediately by adding a Netty's IpFilterHandler to server pipeline as the first handler. It will also stop propagating the upstream channel state events for filtered connection too.
#ChannelHandler.Sharable
public class FilterIPHandler extends IpFilteringHandlerImpl {
private final Set<InetSocketAddress> deniedIP;
public filter(Set<InetSocketAddress> deniedIP) {
this.deniedIP = deniedIP;
}
#Override
protected boolean isAnAccpetedIP(ChannelHandlerContext ctx, ChannelEvent e, InetSocketAddress inetSocketAddress) throws Exception {
return !deniedIP.contains(inetSocketAddress);
}
}

HTTP conversation is not persistent

I need to build a Java server where the client sends an HTTP request, the server sends an HTTP response, the client sends another HTTP request, and the server sends a final response. However, after the server sends the first response to the request, the connection times out. I realized that the client isn't even reading my response until I close the input stream, but this ends the conversation prematurely. Here is the run method for my class ServerThread, which extends Thread.
public void run() {
try {
l.add(index, serv.accept());
new ServerThread(serv, l, index + 1).start();
Socket socket = (Socket)l.get(index);
index++;
while(true) {
while(socket.getInputStream().available() == 0) {}
while(socket.getInputStream().available() > 0)
System.out.print((char)socket.getInputStream().read());
BufferedWriter b = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
b.write("HTTP/1.1 200 OK\n" +
"Connection: keep-alive");
b.flush();
//b.close();
}
} catch (IOException e) {
}
}
Basically, this code accepts a client and blocks until there is information in the input stream. After there is information, it prints out the request and writes a 200 OK response to the client regardless of the request and keep the connection alive. When I comment out the b.close() call, the conversation hangs, but as soon as I stop the server, the client reads the response. How do I get around this?

Java Servlet 3.0 server push: Sending data multiple times using same AsyncContext

Lead by several examples and questions answered here ( mainly
http://www.javaworld.com/javaworld/jw-02-2009/jw-02-servlet3.html?page=3 ), I want to have server sending the response multiple times to a client without completing the request. When request times out, I create another one and so on.
I want to avoid long polling, since I have to recreate request every time I get the response. (and that quite isn't what async capabilities of servlet 3.0 are aiming at).
I have this on server side:
#WebServlet(urlPatterns = {"/home"}, name = "async", asyncSupported = true)
public class CometServlet extends HttpServlet {
public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException {
AsyncContext ac = request.startAsync(request, response);
HashMap<String, AsyncContext> store = AppContext.getInstance().getStore();
store.put(request.getParameter("id"), ac);
}
}
And a thread to write to async context.
class MyThread extends Thread {
String id, message;
public MyThread(String id, String message) {
this.id = id;
this.message = message;
}
public void run() {
HashMap<String, AsyncContext> store = AppContext.getInstance().getStore();
AsyncContext ac = store.get(id);
try {
ac.getResponse().getWriter().print(message);
} catch (IOException e) {
e.printStackTrace();
}
}
}
But when I make the request, data is sent only if I call ac.complete(). Without it request will always timeout. So basically I want to have data "streamed" before request is completed.
Just to make a note, I have tried this with Jetty 8 Continuation API, I also tried with printing to OutputStream instead of PrintWriter. I also tried flushBuffer() on response. Same thing.
What am I doing wrong?
Client side is done like this:
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://localhost:8080/home', true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 3 || xhr.readyState == 4) {
document.getElementById("dynamicContent").innerHTML = xhr.responseText;
}
}
xhr.send(null);
Can someone at least confirm that server side is okay? :)
Your server-side and client-side code is indeed ok.
The problem is actually with your browser buffering text/plain responses from your web-server.
This is the reason you dont see this issue when you use curl.
I took your client-side code and I was able to see incremental responses, with only just one little change:
response.setContentType("text/html");
The incremental responses showed up immediately regardless of their size.
Without that setting, when my output was a small message, it was considered as text/plain and wasnt showing up at the client immediately. When I kept adding more and more to the client responses, it got accumulated until the buffer size reached about 1024 bytes and then the whole thing showed up on the client side. After that point, however, the small increments showed up immediately (no more accumulation).
I know this is a bit old, but you can just flushBuffer on the response as well.

Categories