How to retry lost connections for reliable transmissions? - java

I am sending xml data to server via socket programming. I have found that sometimes when the server is down and the client reports socket timeout, I am unable to send or receive.
I want to handle this exception and try to resend for 3 to 4 times. Should I use Thread.sleep, write in loop, or is there any better approach?
private String sendRequestToChannel(String request) {
String xmlData = null;
BufferedReader rd = null;
BufferedWriter bw = null;
String line = null;
String lineSep = null;
String data = null;
StringBuffer serverData = null;
try {
Socket cliSocket = new Socket();
cliSocket.connect(new InetSocketAddress(HOST, PORT), SOCKET_TIMEOUT);
bw = new BufferedWriter(new OutputStreamWriter(cliSocket.getOutputStream()));
bw.write("POST " + PATH + " HTTP/1.0\r\n");
bw.write("Host: " + HOST + "\r\n");
bw.write("Content-Length: " + request.length() + "\r\n");
bw.write("Pragma: cache\r\n");
bw.write("Cache-Control: private, must-revalidate\r\n");
bw.write("Content-Type: application/x-www-form-urlencoded\r\n");
bw.write("\r\n");
bw.write(request);
bw.flush();
rd = new BufferedReader(new InputStreamReader(cliSocket.getInputStream()));
System.out.println("Step 4 : Getting Input Stream");
serverData = new StringBuffer("");
lineSep = System.getProperty("line.separator");
while ((line = rd.readLine()) != null) {
serverData.append(line);
serverData.append(lineSep);
}
data = serverData.toString();
int index = data.indexOf("<");
if (index != -1) {
xmlData = data.substring(index);
} else {
System.out.println("\r\n \r\n XML Data Not Retrived");
}
} catch (java.net.UnknownHostException uh) {
uh.printStackTrace();
System.out.println("$$$$$$$$$$$$ in sendRequestToChannel : UnknownHostException " + uh.getMessage());
return " in sendRequestToChannel : UnknownHostException " + uh.toString();
} catch (IOException ioe) {
ioe.printStackTrace();
System.out.println("$$$$$$$$$$$$ in sendRequestToChannel : IOException " + ioe.getMessage());
return " in sendRequestToChannel : IOException " + ioe.toString();
} catch (Exception e) {
e.printStackTrace();
System.out.println("$$$$$$$$$$$$ in sendRequestToChannel : Exception " + e.getMessage());
return " in sendRequestToChannel : Exception " + e.toString();
} finally {
try {
if (bw != null) {
bw.close();
}
} catch (IOException ex) {
Logger.getLogger(SA_Caesar.class.getName()).log(Level.SEVERE, null, ex);
}
try {
if (rd != null) {
rd.close();
}
} catch (IOException ex) {
Logger.getLogger(SA_Caesar.class.getName()).log(Level.SEVERE, null, ex);
}
bw = null;
rd = null;
line = null;
lineSep = null;
data = null;
serverData = null;
}
return xmlData;
}

The biggest problem an application faces when its remote service goes down is that there's no way at all to predict when it will return, if ever.
You are already using a TCP connection which will retry when faced with short-term unreachable services, but by the time TCP has declared the connection dead, you actually don't increase reliability by automatically trying to re-establish the connection. For example, if it takes two days for the remote server to come back, will your application be able to act as if it had never been down? Will all necessary data be queued during the outage? Will the semantics of a connected system be preserved across a weekend's failure? How about if the remote service is down for 5 days?
The best that you can do from a system perspective is notify the operator that there is a fault which requires attention. This is why we still have operators and will for the foreseeable future.

Related

Java "while != null" reads last line as null

I am trying to run the following code using a batch file of URLs, while the URL is not null. It runs exactly how I want it to, however, the last line of output reads:
Malformed URL Exception: 'null' is not a valid input
Batch Program Completed Successfully
I want the program to stop right before it actually reads the null. Any suggestions?
(Also, I am still learning how to ask questions without people getting mad at me so if I can improve my question, just let me know instead of down voting. Thanks.)
private static String getBatchUrlContents(String filePath) {
logger.debug(">>getBatchUrlContents()");
String theUrl = "";
try {
FileReader fileReader = new FileReader(filePath);
BufferedReader bufferedUrlReader = new BufferedReader(fileReader);
do {
try {
theUrl = bufferedUrlReader.readLine();
URL url = new URL(theUrl);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
String contentType = urlConnection.getContentType();
logger.info("Content Type: {}", contentType);
int statusCode = urlConnection.getResponseCode();
logger.info("Status Code: {}", statusCode);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
String line;
List<String> contents = new ArrayList<String>();
while ((line = bufferedReader.readLine()) != null) {
contents.add(line);
}
bufferedReader.close();
String[] contentArray = contents.toArray(new String[contents.size()]);
System.out.println("\n ~~~~~~~NEW URL~~~~~~~ \n" + theUrl);
for (String x :contentArray)
System.out.println(x);
String firstLine = contentArray[0];
if (firstLine.equals("#EXTM3U")) {
logger.info("First line is validated: {}", firstLine);
System.out.println("First line of content is validated: " + firstLine);
} else {
logger.error("Error: First line not valid: {}", firstLine);
System.out.println("Error: First line reads: '" + firstLine + "'\n"
+ "Should read: '#EXTM3U'");
}
} catch(Exception e) {
if (e instanceof MalformedURLException) {
logger.error("Malformed URL Exception: {}", e.toString());
System.out.println("Malformed URL Exception: '" + theUrl + "' is not a valid input");
} else if (e instanceof FileNotFoundException) {
logger.error("404: File Not Found Exception: {}", e.toString());
System.out.println("Unable to open URL: " + theUrl);
} else if (e instanceof IOException) {
logger.error("IO Exception: {}", e.toString());
System.out.println("Error reading file: " + theUrl);
} else {
logger.error("Exception: {}", e.toString());
System.out.println("Exception Error - Unable to read or open: " + theUrl);
}
}
} while (theUrl != null);
bufferedUrlReader.close();
} catch (FileNotFoundException ex) {
System.out.println("Unable to open file '" + filePath + "'");
System.exit(2);
} catch (IOException ex) {
System.out.println("Error reading file '" + filePath + "'");
System.exit(3);
}
logger.debug("<<getUrlContents()");
return "Batch Program Completed Successfully";
}
The theUrl != null check happens at the end of the loop; it isn't checked continuously.
If you need theURL to be non-null, you'll need to check for that.
You could do the assignment in the condition (although this is frowned upon in some circles):
while((theUrl = bufferedUrlReader.readLine()) != null) {
URL url = new URL(theUrl);
...
or, just do a check inside the loop and do a manual break:
while(true) {
theUrl = bufferedUrlReader.readLine();
if (!theURL) { // Or "if (theURL == null)"
break;
}
URL url = new URL(theUrl);
...

How to correctly handle HTTP POST in Java

I'm receiving an HTTP POST from a remote server on my code, and I have to extract the JSON that comes with it and confirm reception with a response with the 2xx code.
Here's my code:
try {
ServerSocket serverSocket = new ServerSocket(PORT);
System.out.println("Server started.\nListening for connections on port : " + PORT + " ...\n");
JavaServer myServer = new JavaServer(serverSocket.accept());
System.out.println("Connection opened. (" + new Date() + ")");
long start_time = System.currentTimeMillis();
//sendPOST();
try {
myServer.run();
} catch (Exception e) {
System.out.println("Error");
}
long end_time = System.currentTimeMillis();
System.out.println("Thread took " + (end_time - start_time) / 1000 + " seconds to execute");
serverSocket.close();
} catch (IOException e) {
System.err.println("Server Connection error : " + e.getMessage());
}
}
And in the run() method:
public void run() {
try {
String urlParameters = "200";
DataOutputStream wr = new DataOutputStream(connect.getOutputStream());
wr.writeBytes(urlParameters);
wr.flush();
//wr.close();
BufferedReader in = new BufferedReader(new InputStreamReader(connect.getInputStream()));
String inputLine;
StringBuilder response = new StringBuilder();
while (in.ready()) {
inputLine = in.readLine();
in.read();
response.append(inputLine);
System.out.println(inputLine);
}
in.close();
System.out.println("\n"+response.toString());
wr.close();
} catch (Exception e) {
System.out.println("Error reading input: " + e.getMessage());
}
}
After searching here for the best solution, I could only find questions related to how to send (not receive) an HTTP POST.
I don't think my code is doing what I want it to do correctly (extract the JSON and send a response back) as it takes long to get a small JSON and I think the response is not being received.
Can anyone help?

Why is my data missing from my file after transfering it over a socket?

I have the same code written for both server and client when attempting to upload a file to the server or download it from the server.
Downloading from the server works just fine and no data is missing in my file, but for some reason when uploading the file, not all is transmitted.
For instance, the file size on my client is smaller then when it is on the server. Then when it is opened up on the server, not all of it is there (since not all of it was received)
Server:
Algorithm:
Get message from client
Client tells server it wants to send a file (push)
Server reads where to put the file, and then receives the file from the client
public static void GetClientMessage() {
while (true) {
try {
try {
try {
serverSocket = new ServerSocket(PORT_NUMBER);
} catch (IOException ex) {
System.out.println("GetClientMessage():serverSocket:IOException:ex " + ex);
SendBackException(ex.toString()); // Inform client
}
try {
System.out.println("Waiting for client");
socket = serverSocket.accept();
} catch (IOException ex) {
System.out.println("GetClientMessage():socket = serverSocket.accept():IOException:ex " + ex);
SendBackException(ex.toString()); // Inform client
}
bufOut = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
brffReadIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
// 1 - Read Line (it is the flag)
flag = brffReadIn.readLine();
// 2 - Handle Flag
HandleClientMessage(flag);
// Make decisions based upon that message
} catch (IOException ex) {
System.out.println("GetClientMessage():IOException:ex: " + ex);
SendBackException(ex.toString()); // Inform client
}
socket.close();
serverSocket.close();
} // Close while loop
catch (IOException ex) {
System.out.println("GetClientMessage:serverSocket.close():IOException:ex " + ex);
}
}
}
public static void HandleClientMessage(String message) {
System.out.println("HandleClientMessage:message: '" + message + "'");
switch (message) {
case "push":
GetClientFile();
break;
case "open_cla":
OpenCla();
break;
case "kill_cla":
KillCla();
break;
case "get":
SendFile();
break;
default:
break;
}
}
// Gets path to where to place file on local
public static String GetPath() {
String filePath = " ";
try {
bufOut = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
brffReadIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
filePath = brffReadIn.readLine();
System.out.println("Path to place file on local: " + filePath);
} catch (IOException ex) {
System.out.println(("GetPath():IOException:ex: " + ex));
}
return filePath;
}
public static void GetClientFile() {
// Get the location where to place the file on local
fileOnLocal = GetPath();
int count;
try {
File file = new File(fileOnLocal);
// Get the size of the file
long length = file.length();
byte[] bytes = new byte[16* 1024];
InputStream in = socket.getInputStream();
OutputStream out = new FileOutputStream(fileOnLocal);
while ((count = in.read(bytes)) > 0) {
System.out.println("strByteArray: " + strByteArray);
out.write(bytes, 0, count);
}
out.flush();
System.out.println("File Size in bytes: " + file.length());
if (file.length() < 5) {
System.out.println("FileClient:Error:File:" + fileOnLocal + " not found on server");
out.close();
in.close();
socket.close();
file.delete();
System.out.println("File:" + file.getAbsolutePath() + " deleted");
} else {
out.close();
in.close();
socket.close();
}
} catch (IOException ex) {
System.out.println(":FileClient:GetServerFile():IOException:ex:" + ex);
}
}
Client Code:
Client tells the server it wants to "push" a file, then it passes the location where to put it on the server, then transmits the file
public void SendFlagToServer(String flag){
try {
bufOut = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
brffReadIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
bufOut.write(flag);
bufOut.newLine();
bufOut.flush();
System.out.println(host + ":SendFlagToServer: " + flag);
} catch (IOException ex) {
Logger.Log((host + ":FileClient:SendFileToGetToServer():IOException:ex: " + ex));
}
}
After performing this the bytes are received on the client, but not all of them. Is there something I have coded wrong? Should my byte[] array be a different size? This will be used on Win7 & Win8, and possibly Mac in the future.
Edit: I figured it out. I was trying to send a message followed by a string of bytes too quickly.
This fixed my problem:
SendFlagToServer(fileLocaitonOnServer);
Thread.sleep(1000);
....
You are closing sockets after first client conneciton
socket.close();
serverSocket.close();
Solution:
Once you accept a client socket, create a new Thread with the socket connection and handle all IO operations in that thread
Do not close serverSocket. Once you close serverSocket, no more client socket connections will be accepted.
Can you provide the exception you are getting?

Java Socket doesn't return anything in the stream

When I try to get information from a Socket (it's at localhost) it never returns what I want (info from my server) with php it works fine..
Java application: run & debug doesn't return anything
Glassfish server: run doesn't return anything, debug return all the info, everytime i debug
PHP Code:
$Socket = fsockopen($this->Host, $this->Port, $errno, $errstr, 5);
if(!$Socket) {
return false;
} else {
stream_set_timeout($Socket, 1);
stream_set_blocking($Socket, false);
fwrite($Socket, chr(6).chr(0).chr(255).chr(255).'info');
while(!feof($Socket)) {
$this->SocketData .= fgets($Socket, 8192);
}
fclose($Socket);
return true;
}
Java Code:
public static String serverInfo(String ip, Integer port) {
try (Socket socket = new Socket(ip, port)) {
//System.out.println("Connected to " + socket.getInetAddress() + " on port " + socket.getPort() + " from port " + socket.getLocalPort() + " of " + socket.getLocalAddress());
OutputStream os = socket.getOutputStream();
String info = ((char) 6 + "" + (char) 0 + "" + (char) 255 + "" + (char) 255 + "info");
System.out.println(info);
os.write(info.getBytes());
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
StringBuilder stb = new StringBuilder();
while (br.ready()) {
stb.append(br.readLine());
}
if (!stb.toString().isEmpty()) {
//System.out.println("Info: " + stb.toString());
return stb.toString();
} else {
//System.out.println("No answer from server.");
return null;
}
} catch (UnknownHostException e) {
System.err.println("I can't find " + ip);
} catch (SocketException e) {
System.err.println("Could not connect to " + ip);
} catch (IOException e) {
System.err.println(e);
}
return null;
}
What I was looking for, was to do the same as php does, connect to the socket, get the information and return/save/whatever with that information and I don't know what happens that only 1/100 times that I try, it returns something.
When I run in my web application AND debug, it returns EVERYTIME the info, something is really wrong and I can't figure it out..
PS: It's meant to get OTServer information.
I think this is not the right way to read from the br.
while (br.ready()) {
stb.append(br.readLine());
}
Try changing this to:
String line = null;
while ((line = br.readLine()) != null) {
stb.append(line);
}
Also, call os.close() after this line.
os.write(info.getBytes());

Java Socket not sending message to the server

I have the following client socket for sending a string to the server. The server is not getting message. What could be the prob;em?
public void startClient() throws IOException {
Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
InetAddress host = null;
BufferedReader stdIn = null;
try {
host = InetAddress.getByName("172.16.2.97");
socket = new Socket(host, 52000);
out = new PrintWriter(socket.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
stdIn = new BufferedReader(new InputStreamReader(System.in));
String fromServer;
String fromUser = null;
//ClientHelper.unpackISO();
fromUser = ClientHelper.createISO();
if (fromUser != null) {
//System.out.println("Client - " + fromUser);
out.write(fromUser);
System.out.println("Sent message");
}
while ((fromServer = in.readLine()) != null) {
System.out.println("Server - " + fromServer);
if (fromUser != null) {
//System.out.println("Client - " + fromUser);
out.println(fromUser);
}
}
} catch (ISOException ex) {
Logger.getLogger(ClientDemo.class.getName()).log(Level.SEVERE, null, ex);
} catch (UnknownHostException e) {
System.err.println("Cannot find the host: " + host.getHostName());
System.exit(1);
} catch (IOException e) {
System.err.println("Couldn't read/write from the connection: " + e.getMessage());
System.exit(1);
} finally { //Make sure we always clean up
out.close();
in.close();
stdIn.close();
socket.close();
}
}
The method ClientHelper.createISO() return a string which is supposed to be sent to the server. Unfortunately the server is not getting any string. Could the problem be proxy settings. If so how can solve it. Or is it another problem with my code?
What is the problem with my code?
You must flush() the stream after writing to it. Sockets buffer until you get a full packet otherwise
Check the 5th line below, you need to flush your output stream. Otherwise server will not get any packet and you will stuck on your first in.readLine() because its blocking.
fromUser = ClientHelper.createISO();
if (fromUser != null) {
//System.out.println("Client - " + fromUser);
out.write(fromUser);
out.flush(); // FLUSH IT HERE, packet wont be sent until you flush your stream
System.out.println("Sent message");
}
Also add flush after your out.write(fromUser) inside the loop.

Categories

Resources