Apache http client Read Timed Out - apache-httpclient-4.x

I am using apache http client api 4.5 to access a server. When server is under heavy load I get the error
"[read] I/O error: Read timed out"
Here is my configuration
private CookieStore cookieStore = new BasicCookieStore();
private CloseableHttpClient httpClient;
private final String USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36";
private HttpClientContext httpContext = new HttpClientContext();
private RequestConfig requestConfig = RequestConfig.custom()
.setSocketTimeout(5000).
setConnectTimeout(10000).build();
private PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
public MyHttpClient() {
cm.setMaxTotal(50);
cm.setDefaultMaxPerRoute(10);
HttpHost host = new HttpHost("localhost", 80);
cm.setMaxPerRoute(new HttpRoute(host), 5);
DefaultServiceUnavailableRetryStrategy retryStrategy = new DefaultServiceUnavailableRetryStrategy(5, 1);
SocketConfig socketConfig = SocketConfig.custom()
.setSoKeepAlive(true)
.setSoReuseAddress(true)
.setTcpNoDelay(true)
.setSoTimeout(10000).build();
httpContext.setAttribute(HttpClientContext.COOKIE_STORE, cookieStore);
HttpClientBuilder builder= HttpClients.custom();
builder.setMaxConnPerRoute(50)
.setConnectionManager(cm)
.setConnectionTimeToLive(10000, TimeUnit.MILLISECONDS)
.setDefaultCookieStore(cookieStore)
.setRedirectStrategy(new LaxRedirectStrategy())
.setDefaultSocketConfig(socketConfig)
.setServiceUnavailableRetryStrategy(retryStrategy)
.setKeepAliveStrategy(keepAliveStrategy)
.setRetryHandler(myRetryHandler);
httpClient=builder.build();
}
I understand the cause of the issue
The read timeout is the timeout on waiting to read data
But I want to know
if there is any way/configuration to avoid the read time out error
What may be optimum settings so that my client will not fail when server is under load.
I see a similar post here but not answered Similar issue

I do not think that error message is related to the response above it. Notice the time offset. If it was part of that response it would have the same time stamp as the lines of that response. That is just the point where the time out happened and was logged.

One of the reasons for having such an error may be that the server closes HTTP connections upon having responded. If that is the case, then this error may be avoided by disabling connection reuse by the client, so there would be no need for the client to verify that the connection is still alive:
builder.setConnectionReuseStrategy( (response, context) -> false );

Related

java.net.ConnectException: Connection refused: connect. Data Grip [duplicate]

I'm trying to implement a TCP connection, everything works fine from the server's side but when I run the client program (from client computer) I get the following error:
java.net.ConnectException: Connection refused
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:351)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:213)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:200)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:432)
at java.net.Socket.connect(Socket.java:529)
at java.net.Socket.connect(Socket.java:478)
at java.net.Socket.<init>(Socket.java:375)
at java.net.Socket.<init>(Socket.java:189)
at TCPClient.main(TCPClient.java:13)
I tried changing the socket number in case it was in use but to no avail, does anyone know what is causing this error & how to fix it.
The Server Code:
//TCPServer.java
import java.io.*;
import java.net.*;
class TCPServer {
public static void main(String argv[]) throws Exception {
String fromclient;
String toclient;
ServerSocket Server = new ServerSocket(5000);
System.out.println("TCPServer Waiting for client on port 5000");
while (true) {
Socket connected = Server.accept();
System.out.println(" THE CLIENT" + " " + connected.getInetAddress()
+ ":" + connected.getPort() + " IS CONNECTED ");
BufferedReader inFromUser = new BufferedReader(
new InputStreamReader(System.in));
BufferedReader inFromClient = new BufferedReader(
new InputStreamReader(connected.getInputStream()));
PrintWriter outToClient = new PrintWriter(
connected.getOutputStream(), true);
while (true) {
System.out.println("SEND(Type Q or q to Quit):");
toclient = inFromUser.readLine();
if (toclient.equals("q") || toclient.equals("Q")) {
outToClient.println(toclient);
connected.close();
break;
} else {
outToClient.println(toclient);
}
fromclient = inFromClient.readLine();
if (fromclient.equals("q") || fromclient.equals("Q")) {
connected.close();
break;
} else {
System.out.println("RECIEVED:" + fromclient);
}
}
}
}
}
The Client Code:
//TCPClient.java
import java.io.*;
import java.net.*;
class TCPClient {
public static void main(String argv[]) throws Exception {
String FromServer;
String ToServer;
Socket clientSocket = new Socket("localhost", 5000);
BufferedReader inFromUser = new BufferedReader(new InputStreamReader(
System.in));
PrintWriter outToServer = new PrintWriter(
clientSocket.getOutputStream(), true);
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(
clientSocket.getInputStream()));
while (true) {
FromServer = inFromServer.readLine();
if (FromServer.equals("q") || FromServer.equals("Q")) {
clientSocket.close();
break;
} else {
System.out.println("RECIEVED:" + FromServer);
System.out.println("SEND(Type Q or q to Quit):");
ToServer = inFromUser.readLine();
if (ToServer.equals("Q") || ToServer.equals("q")) {
outToServer.println(ToServer);
clientSocket.close();
break;
} else {
outToServer.println(ToServer);
}
}
}
}
}
This exception means that there is no service listening on the IP/port you are trying to connect to:
You are trying to connect to the wrong IP/Host or port.
You have not started your server.
Your server is not listening for connections.
On Windows servers, the listen backlog queue is full.
I would check:
Host name and port you're trying to connect to
The server side has managed to start listening correctly
There's no firewall blocking the connection
The simplest starting point is probably to try to connect manually from the client machine using telnet or Putty. If that succeeds, then the problem is in your client code. If it doesn't, you need to work out why it hasn't. Wireshark may help you on this front.
You have to connect your client socket to the remote ServerSocket. Instead of
Socket clientSocket = new Socket("localhost", 5000);
do
Socket clientSocket = new Socket(serverName, 5000);
The client must connect to serverName which should match the name or IP of the box on which your ServerSocket was instantiated (the name must be reachable from the client machine). BTW: It's not the name that is important, it's all about IP addresses...
I had the same problem, but running the Server before running the Client fixed it.
One point that I would like to add to the answers above is my experience-
"I hosted on my server on localhost and was trying to connect to it through an android emulator by specifying proper URL like http://localhost/my_api/login.php . And I was getting connection refused error"
Point to note - When I just went to browser on the PC and use the same URL (http://localhost/my_api/login.php) I was getting correct response
so the Problem in my case was the term localhost which I replaced with the IP for my server (as your server is hosted on your machine) which made it reachable from my emulator on the same PC.
To get IP for your local machine, you can use ipconfig command on cmd
you will get IPv4 something like 192.68.xx.yy
Voila ..that's your machine's IP where you have your server hosted.
use it then instead of localhost
http://192.168.72.66/my_api/login.php
Note - you won't be able to reach this private IP from any node outside this computer. (In case you need ,you can use Ngnix for that)
I had the same problem with Mqtt broker called vernemq.but solved it by adding the following.
$ sudo vmq-admin listener show
to show the list o allowed ips and ports for vernemq
$ sudo vmq-admin listener start port=1885 -a 0.0.0.0 --mountpoint /appname --nr_of_acceptors=10 --max_connections=20000
to add any ip and your new port. now u should be able to connect without any problem.
Hope it solves your problem.
Hope my experience may be useful to someone. I faced the problem with the same exception stack trace and I couldn't understand what the issue was. The Database server which I was trying to connect was running and the port was open and was accepting connections.
The issue was with internet connection. The internet connection that I was using was not allowed to connect to the corresponding server. When I changed the connection details, the issue got resolved.
In my case, I gave the socket the name of the server (in my case "raspberrypi"), and instead an IPv4 address made it, or to specify, IPv6 was broken (the name resolved to an IPv6)
In my case, I had to put a check mark near Expose daemon on tcp://localhost:2375 without TLS in docker setting (on the right side of the task bar, right click on docker, select setting)
i got this error because I closed ServerSocket inside a for loop that try to accept number of clients inside it (I did not finished accepting all clints)
so be careful where to close your Socket
I had same problem and the problem was that I was not closing socket object.After using socket.close(); problem solved.
This code works for me.
ClientDemo.java
public class ClientDemo {
public static void main(String[] args) throws UnknownHostException,
IOException {
Socket socket = new Socket("127.0.0.1", 55286);
OutputStreamWriter os = new OutputStreamWriter(socket.getOutputStream());
os.write("Santosh Karna");
os.flush();
socket.close();
}
}
and
ServerDemo.java
public class ServerDemo {
public static void main(String[] args) throws IOException {
System.out.println("server is started");
ServerSocket serverSocket= new ServerSocket(55286);
System.out.println("server is waiting");
Socket socket=serverSocket.accept();
System.out.println("Client connected");
BufferedReader reader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
String str=reader.readLine();
System.out.println("Client data: "+str);
socket.close();
serverSocket.close();
}
}
I changed my DNS network and it fixed the problem
You probably didn't initialize the server or client is trying to connect to wrong ip/port.
Change local host to your ip address
localhost
//to you local ip
192.168.xxxx
I saw the same error message ""java.net.ConnectException: Connection refused" in SQuirreLSQL when it was trying to connect to a postgresql database through an ssh tunnel.
Example of opening tunel:
Example of error in Squirrel with Postgresql:
It was trying to connect to the wrong port. After entering the correct port, the process execution was successful.
See more options to fix this error at: https://stackoverflow.com/a/6876306/5857023
In my case, with server written in c# and client written in Java, I resolved it by specifying hostname as 'localhost' in the server, and '[::1]' in the client. I don't know why that is, but specifying 'localhost' in the client did not work.
Supposedly these are synonyms in many ways, but apparently, not not a 100% match. Hope it helps someone avoid a headache.
For those who are experiencing the same problem and use Spring framework, I would suggest to check an http connection provider configuration. I mean RestTemplate, WebClient, etc.
In my case there was a problem with configured RestTemplate (it's just an example):
public RestTemplate localRestTemplate() {
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress("localhost", <some port>));
SimpleClientHttpRequestFactory clientHttpReq = new SimpleClientHttpRequestFactory();
clientHttpReq.setProxy(proxy);
return new RestTemplate(clientHttpReq);
}
I just simplified configuration to:
public RestTemplate restTemplate() {
return new RestTemplate(new SimpleClientHttpRequestFactory());
}
And it started to work properly.
There is a service called MySQL80 that should be running to connect to the database
for windows you can access it by searching for services than look for MySQL80 service and make sure it is running
It could be that there is a previous instance of the client still running and listening on port 5000.

multiple SockJs connections

I am trying to create handler for SockJs connections which handle multiple users simultaneously like this:
#Bean
public WebSocketHandler snakeHandler() { return new PerConnectionWebSocketHandler(SnakeHandler.class); }
And with code on client side:
Game.socket = new SockJS('/snake/snake');
Game.socket.onopen = function () {
Console.log('Info: WebSocket connection opened.');
Console.log('Info: Press an arrow key to begin.');
};
The problem is with next connection, not first. When I connect at first, I got single WebSocketSession. But all next, got 3 connections:
WebSocketSession, XhrStreamingSockJsSession and PollingSockJsSession and no messages "Info: WebSocket connection opened." in browser console, only first client gets it.
Any ideas?

Does the ConnectionPool from SqlJocky require a close

I'm creating a back-end server application in Dart which is using a MySQL database to store data. To make the SQL call I'm using the ConnectionPool from SqlJocky.
What I do when the app starts:
Create a singleton which store the ConnectionPool
Execute multiple queries with prepareExecute and query
Locally this approach is working fine. Now I pushed a development version to Heroku and I'm getting connection issues after a few minutes.
So I wonder, do I need to close/release a single connection from the pool I use to execute a query? Or is the connection after the query placed again in the pool and free for use?
The abstract base class for all the MySQL stores:
abstract class MySQLStore {
MySQLStore(ConnectionPool connectionPool) {
this._connectionPool = connectionPool;
}
ConnectionPool get connectionPool => this._connectionPool;
ConnectionPool _connectionPool;
}
A concrete implementation for the method getAll:
Future<List<T>> getAll() async {
Completer completer = new Completer();
connectionPool.query("SELECT id, name, description FROM role").then((result) {
return result.toList();
}).then((rows) {
completer.complete(this._processRows(rows));
}).catchError((error) {
// TODO: Better error handling.
print(error);
completer.complete(null);
});
return completer.future;
}
The error I get:
SocketException: OS Error: Connection timed out, errno = 110, address = ...
This doesn't fully answer your question but I think you could simplify your code like:
Future<List<T>> getAll() async {
try {
var result = await connectionPool.query(
"SELECT id, name, description FROM role");
return this._processRows(await result.toList());
} catch(error) {
// TODO: Better error handling.
print(error);
return null;
}
}
I'm sure here is no need to close a connection with query. I don't know about prepareExecute though.
According to a comment in the SqlJocky code it can take quite some time for a connection to be released by the database server.
Maybe you need to increase the connection pool size (default 5) so you don't run out of connections while ConnectionPool is waiting for connections to be released.
After some feedback from Heroku I managed to resolve this problem by implementing a timer task that does every 50 seconds a basic MySQL call.
The response from Heroku:
Heroku's networking enforces an idle timeout of 60-90 seconds to prevent runaway processes. If you're using persistent connections in your application, make sure that you're sending a keep-alive at, say, 55 seconds to prevent your open connection from being dropped by the server.
The work around code:
const duration = const Duration(seconds: 50);
new Timer.periodic(duration, (Timer t) {
// Do a simple MySQL call with on the connection pool.
this.connectionPool.execute('SELECT id from role');
print('*** Keep alive triggered for MySQL heroku ***');
});

httpClient connection is in time_wait status in multiple threads code

I need to write a code to send a server request consequently, the request is xml format string. After doing research, I select to use multiple threads and connection pool manager to handle the request and response . I use PoolingHttpClientConnectionManager, httpclient 4.3 version. When I use one thread, the code works, send request and get the response. But when I make it as multiple thread and using single httpclient, the connection seems broken. I use netstat to check and see the TCP status is TIME_WAIT. My code is like:
PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
cm.setMaxTotal(50);
cm.setDefaultMaxPerRoute(10);
cm.setMaxPerRoute(new HttpRoute(new HttpHost(ENV_ ABCD)), 20);
CloseableHttpClient httpclient = HttpCleints.custom().setConnectionManager(cm).build();
I use thread pool too, each thread is used to handle one task (runnable). The task includes generating one request, sending the request to the server and getting and processing the response, once this task finish, the thread is put back to the thread pool and the connection is also put back to the connection pool.
All requests are sent to the same server so far.
The runnable task includes following line code:
HttpPost post = new HttpPost(url);
try {
// the request is xml string
post.setEntity(new StringEntity(request));
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
String responseStr = null;
try {
// the commonHttpClient is same instance of httpclient declared above.
HttpResponse response = commonHttpClient.execute(post);
HttpEntity entity = response.getEntity();
if (entity != null){
responseStr = getString(entity.getContent());
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
I do not get any response. I can see the code is hanging on the line of “commonHttpClient.execute(post);”. From the netstat, it tells the client side is close the connection.
I do not have this problem if there is only one thread. Can anyone tell me what part of my code is wrong. Do I miss any step to configure connection? It is hard to find the example using apache httpclient 4.3.
Thanks

JavaMail SMTPSendFailedException

I am writing a bulk email program using the JavaMail api. I have a Microsoft Exhange server which I am trying to send the emails in to. When I run my program I get the following error:
**com.sun.mail.smtp.SMTPTransport.issueSendCommand(SMTPTransport.java:2057)
at com.sun.mail.smtp.SMTPTransport.finishData(SMTPTransport.java:1862)
at com.sun.mail.smtp.SMTPTransport.sendMessage(SMTPTransport.java:1100)
at javax.mail.Transport.send0(Transport.java:195)
at javax.mail.Transport.send(Transport.java:124)
at SendEmail.postMail(SendEmail.java:100)
at EmailGenerator.main(EmailGenerator.java:52)**
The part of my code trying to send the message is as follows:
Properties props = new Properties();
props.put("mail.smtp.host", email_server);
props.put("mail.transport.protocol", "smtp");
props.put("mail.smtp.auth", true);
class EmailAuthenticator extends Authenticator {
String user;
String pw;
EmailAuthenticator (String FROM, String PASSWORD)
{
super();
this.user = FROM;
this.pw = PASSWORD;
}
public PasswordAuthentication getPasswordAuthentication()
{
return new PasswordAuthentication(user, pw);
}
}
Session session = Session.getInstance(props, new EmailAuthenticator(USER, PASSWORD));
session.setDebug(debug);
System.out.println("Session created");
.. CREATED MESSAGE HERE...
Transport transport = session.getTransport("smtp");
transport.connect(exchange_server,user,password);
transport.send(msg);
transport.close();
I wonder am I missing some configuration on the Exchange server side, or is an issue with my code?
OK I figured out where I was going wrong here and am posting up the answer incase anybody else can get some value out of it. I had the following line of code:
props.put("mail.smtp.auth", true);
This was telling my application that it needed to authenticate to the SMTP server, when in fact it didnt. This was causing my application from logging into the SMTP server and sending the email and thus producing the error message. Setting this property to false or not having this line of code fixed the issue for me. This line of code is only necessary for SMTP servers that require you to login, which my Exchange server didnt.