I want to reuse channel for multiple HTTP requests. I'm using java+netty for the server but clients could be written in C#/Java.
For the C# client I'm using HttpWebRequest with KeepAlive = true; and I don't close the channel after the arrival of the response. And it works perfect.
But when I tried the same for java <--> java communication I had some problems. I'm handling the responses from server something like in this sample and this client part.
If in if (msg instanceof LastHttpContent) { section I just do ctx.close(); I won't be able to reuse this channel again. What should I do here to be able to reuse it?
I tried:
ctx.write(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE));
or
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER);
or tried to do nothing...but when I try to reuse this channel, i have problem in this handle. The first request was handled fine, but the second gives me this error:
channelRead0: DefaultHttpResponse(decodeResult: failure(java.lang.NullPointerException), version: HTTP/1.1)
Section if (msg instanceof HttpResponse) works fine (I mean headers was read), but throws exception somewhere after that.
And:
headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
doesn't help too. To make it clear: 1st request/response is fine. Second request in same stream is fine, but there is a problem in decoding the response.
I checked Logger. 1st and second responses are equal, so I don't understand why it gets NullException when decoding it.
p.s. netty 4.0.26
You are entirely at the mercy of the clients. If they implement connection pooling, your connection will be reused. If not, not. Nothing you can do about it at the server end except observe and implement the Connection: close header if sent.
Related
This question already has answers here:
Java socket API: How to tell if a connection has been closed?
(9 answers)
Closed 2 years ago.
So I'm in the making of a very simple server/client complex using java. So far I have managed to figure out what happens if the client quits, because then the server receives null while listening from any input from the client.
BUT - what happens if the client is connected and the server quits for any reason... the server is supposed to wait for input from the client, but how can the client know that the server is not listening anymore? For me the clients call to the server just goes into the void... nothing happens...
Can I do something to find out when the server goes down? Time-out, ping/pong or something?
As You surely can see I'm quite new at this, I'm just curious. This was a puzzle for me ever since I attended computer science at the university.
Thanks in advance. dr_xemacs.
(I am assuming you are working with blocking server socket and socket and not with non blocking ones)
Similarly to the server, reading from streams of a closed connection will return null.
However if you instead do not want to rely on this or a scared that the connection to the server could somehow persist, you can also use time outs (check this out! ) which will throw SocketTimeoutException when the time is up and, to keep track of whether the server is up or not, create a ping/packet to assure server is still up and running.
Edit: I did a quick search and this could be useful to you! Take a look!
How can the client know that the server is not listening anymore?
If the client doesn't attempt to interact at some level with the service, it won't know.
Assuming that the client has sent a request, a few different scenarios.
If the service is no longer listening on the designated port, the client will typically get a "Connection Refused" exception.
If the service is still running (in a sense) but it is not working properly, then connection attempts from the client are likely to time out.
If the service's host is down, the client liable get a timeout.
If there are network connectivity or firewall issues, the client could get a timeout or some other exception.
Can I do something to find out when the server goes down? Time-out, ping/pong or something?
You attempt to connect and send a request. If it fails or times out, that means the service is down. If you are designing and implementing the service yourself, you could include a special "healthcheck" request for clients to "ping" on. But the flip-side is that network and server resources will be consumed in receiving and responding to these requests. It can affect your ability to scale up the number of clients, for example, if each client pings the service every N seconds.
But a client typically doesn't need to know whether the service is up or down. It typically only cares that service responds when it it sends a real request. And the simplest way to handle that is to just send the request and deal with the outcome. (The client code has to deal with all possible outcomes anyway when doing a real request. The service can go down, etc between the last healthcheck ping and when the client sends a real request.)
Bottom line: Don't bother with checking availability in the client unless the application (i.e. the end user) really needs to know.
Your Server probably may be running on a certain port and so you can add a health check at the client side and update a global flag with status to let client know about its availibity :-
Socket socket = null;
try
{
socket = new Socket(host, port);
return true;
}
catch (Exception e)
{
return false;
}
finally
{
if(socket != null)
try
{
socket.close();
}
catch(Exception e){}
}
I am investigating a quite strange problem. The project I'm working on uses Spring-remoting to invoke methods over http. From what I have gathered so far the following happens:
My client code executes a request to the server
The server starts handling the request, but is slow
25-30 seconds later, a new request comes in to the server
The second request finishes, the client continues its processing
A while later, the first request get completed, but the client no longer cares
Since my client code executes only one request to the Spring remoting client, and the client continuous on after the second invocation it receives is completed, I can only conclude that this occurs somewhere in the Spring remoting client.
The client uses AbstractHttpInvokerRequestExecutor to make the actual http-invocation, and this in turn uses SimpleHttpInvokerRequestExecutor to make the request. But, from what I can read, this has no mechanism to retry the requests. So now I'm quite stuck.
Can anyone think of what might cause this behaviour? (I have tried to keep the question clean, but I have more details if needed.)
Just an idea to give you some direction, not necessarily a solution. Use a third party Http client (not one from Spring) to see if it changes a behavior. That might help you to see if it is SimpleHttpInvokerRequestExecutor that is "guilty" of re-try or something else. Here is a very simple 3d party HttpClient: Provided in MgntUtils Open source library (written by me). Very simple in use. Take a look at Javadoc. Library itself provided as Maven artifacts and on Git (including source code and Javadoc). All in all your code may look like this:
private static void testHttpClient() {
HttpClient client = new HttpClient();
client.setContentType("application/json");
String content = null;
try {
content = client.sendHttpRequest("http://www.google.com/", HttpMethod.GET);
//content holds the response. Do your logic here
} catch (IOException e) {
//Error Handling is here
content = TextUtils.getStacktrace(e, false);
}
}
Intro
My code can process all bytes that are sent to a server and decide whether or not to let them go through and eventually send responses. I would like to use this to use the server as web server, web socket server and tcp server in one.
Although my code is written for Minecraft, I am not asking this on a Minecraft forum because answering this question doesn't require any prior knowledge about Minecraft or its codebase.
All you need to know about Minecraft
Minecraft is a Java game that can be played online. When it is being played online, there is a server that opens a ServerSocket and all players have their own client that opens a Socket that will communicate with the ServerSocket of the server.
Anyone can create a Minecraft server and install server-side modifications on their server (for those who know Minecraft, these are usually called plug-ins). My application is such a server-side modification. Most Minecraft servers are being hosted by Minecraft host companies. The owners of the servers have some kind of access to the part of the host computer that manages the server files.
Goal
The goal of my modification is to let the Minecraft server serve more clients than just the Minecraft clients. I would like the same server to also work as web server (for http and https requests) as well as (secure) web socket server and tcp server.
Why no multiple server sockets
The most common solution would be to just create a ServerSocket for the other server types and assign a different port to all of them. However, that is not an option in my case. Most hosts forbid you to open other ports or ask extra money for it. So I need to do it all with just the Minecraft ServerSocket.
What I achieved so far
So far, I have managed to let all bytes that are sent to the minecraft server first go through my code. My code can choose whether or not to let the bytes continue to the Minecraft server code. It can also send responses on its own without the need to inform the Minecraft server code at all.
In principle, what I have managed to do is sufficient to accomplish my goal, but I would like some help with how to continue. I will explain below what I have and have not accomplished so far.
The first byte that is sent by a Minecraft client to the server is always the same, namely 16. This is great because it allows me to easily distinguish Minecraft clients from web browsers and tcp clients.
HTTP requests and websocket connections always start with the same byte, namely 71. HTTPS and secure websockets always start with the byte 22. The TCP connections I was talking about will be sent by my own applications, so I can choose exactly what bytes they will send and I can simply program my modification to respond to that.
I managed to distinguish http requests and websocket connections by their connection property. Http requests always send 'Connection: keep-alive' while websocket connections always send 'Connection: upgrade'. (Although some browsers do the k, a and u in uppercase and others do not.)
Handling normal http requests wasn't very hard to do. Handling TCP connections won't be hard either because I will control everything. But I have issues with the remaining connection types:
Problems I need help with
The web socket protocol is quite large and I would prefer not to handle it completely with only my code. (I tried this before, but I kept having problems with the parts that were rarely used and thus not tested.) So I would like to use some library that allows me to only worry about the payload rather than the entire protocol. Unfortunately, web socket libraries generally want to create the ServerSocket, which is not possible in my case. So does anyone have advice on what to do here?
I haven't found any info on how to read https requests properly. Could someone tell me where to look for the details of this protocol or provide a nice link?
For secure web sockets, I will face the same problems as with the 'normal' web socket connections after I find out how to read the requests.
Code
All my code so far can be found at https://github.com/knokko/Multi-Purpose-Server. The most interesting part is probably the part where my code gets the opportunity to process all bytes before they arrive at the Minecraft code, that code is shown below.
Short question(s)
For those who didn't understand exactly what my question (you could see it as 2 questions that are strongly related) is:
-How I should read https requests and secure web socket handshakes?
-Does anyone know a library that can handle web socket input that doesn't require to create the ServerSocket itself?
// This channel handler will be registered for every connection client that will
// inspect
// any message before it reaches the Minecraft code.
pipeline.addFirst("multipurpose_handler_inspector", new ChannelInboundHandlerAdapter() {
private boolean deactivated;
private ChannelListener listener;
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
//super.channelRead will send the content to the minecraft code
try {
if (!deactivated) {
ByteBuf message = (ByteBuf) msg;
if (listener != null) {
listener.read(ctx, message);
} else {
byte firstByte = message.getByte(0);
// All Minecraft connections start with the byte 16
if (firstByte == 16) {
deactivated = true;
super.channelRead(ctx, msg);
}
// All insecure web connections start with the byte 71
else if (firstByte == 71) {
byte[] data = new byte[message.readableBytes()];
message.getBytes(0, data);
WebHandler.Type type = WebHandler.determineConnectionType(data);
if (type == WebHandler.Type.HTTP) {
listener = new HTTPListener();
listener.readInitial(ctx, message);
} else if (type == WebHandler.Type.WEBSOCKET) {
// TODO Find a nice way to handle web socket connections
listener = new WebSocketListener();
listener.readInitial(ctx, message);
} else {
deactivated = true;
super.channelRead(ctx, msg);
}
}
// All secure web connections start with the byte 22
else if (firstByte == 22) {
// TODO implement the secure web protocols and find a way to read this stuff
// and find the difference
System.out.println(
"We are dealing with a secure websocket or https connection");
byte[] data = new byte[message.readableBytes()];
message.getBytes(0, data);
System.out.println(new String(data));
}
// My applications
else if (firstByte == 31) {
listener = new TCPListener();
listener.readInitial(ctx, message);
} else {
System.out.println("Unknown connection type");
deactivated = true;
super.channelRead(ctx, msg);
}
}
} else {
super.channelRead(ctx, msg);
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
});
If you can ALWAYS identify the Minecraft traffic, your best bet might be to run an apache/httpd and/or tomcat server on the same box and forward all non-Minecraft traffic to it. If you do this, the HTTPS stuff might just be a matter of correctly configuring the http server for https traffic.
You may have to configure your code as an http proxy--in fact (Just thought of this) you might want to go out and look for an open source http proxy and just tweak it with your code to extract Minecraft traffic and forward it before doing the rest of the proxy stuff.
I wouldn't do the HTTPs stuff from scratch, it's not terribly difficult but I'd call it non-trivial.
Oh and if your problem is "differentiating Minecraft HTTPS traffic from other HTTPS connections on the same port" I can't help except to say that this might be a good subject for your question :)
I had code working with TcpNioClientConnectionFactory and it has been working fine. Until recently when I made change so that the TCP client perform failover in case of down time of server by using FailoverClientConnectionFactory and it starts to return me response for different request, even for single AbstractClientConnectionFactory provided to the Failover factory.
My code is using #MessagingGateway and the method is wrapped using CompletableFuture however even without CompletableFuture it still return wrong response (most of the time).
The log file is showing
ERROR o.s.i.i.t.TcpOutboundGateway - Cannot correlate response - no pending reply
I can always reproduce this issue using IT test.
Please help.
I am new here so forgive me if I am not familiar with standard operating procedure, but I have researched this topic at length and haven't found a lot of info.
I am trying to implement a client in a Java Http Servlet that can subscribe to a server-sent-event stream and parse data from that stream. Every time I have a client POST a request to my Http servlet, I need to pass on some data from that client to another server and then open an SSE listener, as that is how the other server will notify me it has data for me to hand back to the client.
It needs to be asynchronous and probably multi-threaded because I will have many requests from the client happening in a short time frame and I need to catch every event coming back from the server. The data I pass back from the server to the client can be large so I need threading so I don't miss new events coming in.
I am at a loss for where to start. I have tried implementing some of the example code using the Jersey SSE API (https://jersey.java.net/documentation/latest/sse.html) but when I implement their asynchronous SSE event handling example, the events coming in happen too fast for my handler to process all the data back to the client and the function gets called again from a new event before it finishes, or at least that's what seems to be happening.
Here is a synopsis of what I have written so far:
Client client = ClientBuilder.newBuilder().register(SseFeature.class).build();
WebTarget target = client.target("Target URL");
EventSource eventSource = new EventSource(target) {
#Override
public void onEvent(InboundEvent inboundEvent){
if ("in".equals(inboundEvent.getName())) {
//Check if the event is of the type we care about
//If it is, open an input stream to read the payload and store in a byte array via an HttpURLConnection object
//Open an output stream and stream the payload to a client via an HttpServletResponse Object - This never seems to happen
}
}
};
}
I know it's sloppy, I'm not as familiar with Java so I am just piecing things together so I apologize for that.
This gets called from within my servlet class but it never makes it to the point where I write to the output stream, I think because it's getting interrupted by another event coming in. If anyone has insight into how I can make this work, or another way to do it, I would greatly appreciate it. Thanks.
I recommend you the JEaSSE library (Java Easy Server-Sent Events): http://mvnrepository.com/artifact/info.macias/jeasse
You can find some usage examples here:
https://github.com/mariomac/jeasse