Java TCP BufferedOutputStream reconnection strategy - java

I have an application that has to send data via TCP socket to another application. This is a 1 way stream from client to server. When sending data the client must retry/reconnect and try to insure all data is sent should the receiver/listener/server die/disappear or drop the connection. My code is as follow:
public class TCPSocket implements Closeable {
private static final int SIXTY_FOUR_KB = 65536;
private final String ip;
private final int port;
private Socket socket;
private BufferedOutputStream writer;
public TCPSocket(String ip, int port) {
this.ip = ip;
this.port = port;
}
public TCPSocket connect() throws ConnectException {
try {
socket = new Socket(ip, port);
socket.setSendBufferSize(SIXTY_FOUR_KB);
writer = new BufferedOutputStream(socket.getOutputStream(), SIXTY_FOUR_KB);
} catch (Exception e) {
throw new ConnectException(e.getMessage());
}
return this;
}
public void write(String message) throws InterruptedException {
boolean succeeded = true;
do {
try {
writer.write(message.getBytes(StandardCharsets.UTF_8));
writer.write("\n".getBytes(StandardCharsets.UTF_8));
} catch (Exception e) {
System.out.println(e.getMessage());
succeeded = false;
// Exponential backoff to go here
try {
System.out.println("Attempting reconnection");
tryClose();
connect();
} catch (ConnectException connectException) {
System.out.println(connectException.getMessage());
}
}
} while (!succeeded);
}
private void tryClose() {
try {
close();
} catch (Exception ex) {
System.out.println("Failed closing TCPSocket");
}
}
#Override
public void close() throws IOException {
if (writer != null) {
writer.flush();
writer.close();
writer = null;
}
if (socket != null && !socket.isClosed()) {
socket.close();
socket = null;
}
}
}
N.B: Reason for using the BufferedOutputStream is because I'm sending small messages and all other methods couldn't get the same throughput in real world test scenario.
This all works as expected for me however I have a few points.
Is this the right way to do this or totally insane and will cause
serious problems?
When trying to clean up and close connections and the writer before
opening a new connection the following error is thrown and I am
unable to close the bufferedOutputStream
java.net.SocketException: Connection reset by peer: socket write error
If I socket.shutdownOutput(); before attempting to close the output stream then that also throws an exception. What is the correct way to clean up and reconnect?

Related

Java socket programming fails to close the connection gracefully [duplicate]

I have written a program given below. It accept some data from client & returns success in response. Sometimes it throws connection reset error & due to which some socket connection remain unclose result. Any idea how to handle connection reset error when client code tries to communicate & connection is closed by client automatically?
import java.net.*;
import java.io.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class tcp_server implements Runnable {
private final Socket server;
private PrintWriter toClient = null;
private BufferedReader fromClient = null;
public tcp_server(Socket s) {
this.server = s;
}
#Override
public void run() {
String name = "";
synchronized (server) {
try {
server.setSoTimeout(6000);
toClient
= new PrintWriter(server.getOutputStream(), true);
fromClient
= new BufferedReader(
new InputStreamReader(server.getInputStream()));
String line = "";
String data = "";
while ((line = fromClient.readLine()) != null) {
data = data + line;
toClient.println("{status:success}");
break;
}
} catch (Exception eb) {
System.out.println("{status:error,Reason:" + eb.getMessage() + "}");
} finally {
// System.out.println("Finally not called if timeout occurs");
if (toClient != null) {
toClient.close();
}
if (fromClient != null) {
try {
fromClient.close();
} catch (IOException ex) {
Logger.getLogger(tcp_server.class.getName()).log(Level.SEVERE, null, ex);
}
}
try {
server.close();
} catch (IOException ex) {
Logger.getLogger(tcp_server.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
public static void main(String[] args) throws IOException {
int serverPort = 40820;
ServerSocket serverSocket = new ServerSocket(serverPort);
synchronized (serverSocket) {
for (;;) {
Socket server = serverSocket.accept();
new Thread(new tcp_server(server)).start();
}
}
}
}
This is better code ... but still with same error "Connection reset" though applied timeout to 60sec
You handle it by closing the connection, of course.
The real question is why did you get it? There are several common causes:
you wrote to a connection that had already been closed by the peer
you closed a connection without reading data that had already arrived in the socket receive buffer. This will reset the peer.
Both of these are application protocol errors that should be fixed. There isn't any point in sending data that won't be read.

Problem in establishing connection in HTTPS in proxy server.(CONNECT Method)

I am developing a proxy server based on java. For simple http request, proxy server is working. But for HTTPS Connection, connection gets timed out. Here are the steps I did. I first read one line from input stream and created a socket connecting Server. After that I gave 200 Status to client. After that I asynchronously read and write between Client Socket and Server socket. But currently this isn't working and connection gets timedout and I couldn't debug the problem.
public class ProxyServer extends Thread {
private String host;
private int port;
private ServerSocket serverSocket;
private InputStream proxyToClientIP;
private OutputStream proxyToClientOP;
private InputStream proxyToServerIP;
private OutputStream proxyToServerOP;
private Socket socket;
private Socket socketFromProxyServer;
ProxyServer(ServerSocket serverSocket, Socket socket) {
this.serverSocket = serverSocket;
this.socket = socket;
this.start();
}
public void run() {
processInputRequest();
}
public void processInputRequest() {
try {
proxyToClientIP = socket.getInputStream();
proxyToClientOP = socket.getOutputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(proxyToClientIP));
String hostDetails = reader.readLine();
System.out.println(hostDetails);
boolean isConnect = false;
//Need to parse request and find req type as GET or CONNECT
//As of now we assume it to be Connect request
if (!isConnect) {
processGetRequest();
} else {
processConnectRequest();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
public void processConnectRequest() {
//Need to get host name from request. Currently Hardcoded for developing purpose
host = "harish-4072";
port = 8383;
try {
socketFromProxyServer = new Socket(host, port);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(proxyToClientOP));
writer.write("HTTP/1.1 200 Connection established\r\n" + "\r\n");
writer.flush();
proxyToServerOP = socketFromProxyServer.getOutputStream();
proxyToServerIP = socketFromProxyServer.getInputStream();
proxyRequest();
} catch (IOException ex) {
System.out.println(ex);
}
}
public void proxyRequest() {
try {
new Thread() {
#Override
public void run() {
try {
byte[] read = new byte[1024];
int in;
System.out.println("Reading");
while ((in = proxyToClientIP.read(read)) != -1) {
proxyToServerOP.write(read, 0, in);
proxyToServerOP.flush();
}
} catch (SocketException e) {
System.out.println(e);
} catch (IOException ex) {
}
}
}.start();
byte[] reply = new byte[1024];
int out;
System.out.println("Writing");
while ((out = proxyToServerIP.read(reply)) != -1) {
proxyToClientOP.write(reply, 0, out);
proxyToClientOP.flush();
}
} catch (IOException ex) {
}
public void processGetRequest() {
//
}
}
I first read one line from input stream and created a socket connecting Server. ... After that I asynchronously read and write between Client Socket and Server socket.
The problem is that you are reading only a single line while you would need to read the full HTTP request header from the client, i.e. everything up to the end of the request header (\r\n\r\n).
Because you fail to do so the unread parts of the HTTP request are forwarded to the server. But the server is expecting the start of the TLS handshake and these data confuse the server. This might result in hanging or aborting, depending on the content of the data and one the kind of server.

java.net.SocketException: Software caused connection abort: socket write error when resubmitting the request

working with sockets on this problem. I wrote the implementation of Http and TCP servers. HTTP works completely correctly, so I can send requests to the server one by one. What can not be said about the TCP server, the first request leaves and is handled correctly, but when you try to send the following request, throws this exception:
java.net.SocketException: Software caused connection abort: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111)
at java.net.SocketOutputStream.write(SocketOutputStream.java:134)
at java.io.DataOutputStream.writeBytes(DataOutputStream.java:276)
at Main.main(Main.java:24)
After that, the client side is closed, and the server side continues to work.HTTP and TCP are implemented from the same Server class, which starts the server.
MyServer:
public abstract class Server implements Runnable {
private final Socket clientSocket;
public Server(Socket clientSocket) {
this.clientSocket = clientSocket;
}
#Override
public void run() {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
BufferedWriter output = new BufferedWriter(new PrintWriter(clientSocket.getOutputStream()))) {
String req = getRequest(reader);
setResponse(output, req);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Class that starts the server:
public class RunServer extends Thread {
private final int port;
private ExecutorService executorService;
private String serverType;
private ServerFactoryContainer serverFactoryContainer;
public RunServer(String serverType, int port) {
this.port = port;
this.executorService = Executors.newFixedThreadPool(4);
this.serverType = serverType;
this.serverFactoryContainer = new ServerFactoryContainer();
}
#Override
public void run() {
try {
ServerSocket serverSocket = new ServerSocket(port);
while (!isInterrupted()) {
Socket clientSocket;
try {
clientSocket = serverSocket.accept();
executorService.execute(serverFactoryContainer.getServerFactory(serverType).createServer(clientSocket));
} catch (IOException e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
TCP client-side:
public class Main {
public static void main(String[] args) throws IOException {
String req;
String resp;
try (Socket clientSocket = new Socket(InetAddress.getLocalHost(), Constants.ServerConstant.TCP_PORT);
BufferedReader inFromClient = new BufferedReader(new InputStreamReader(System.in));
DataOutputStream outToServer = new DataOutputStream(clientSocket.getOutputStream());
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()))) {
while (true) {
System.out.println("Write command [get count] or [get item]");
req = inFromClient.readLine().toLowerCase();
outToServer.writeBytes(req + "\n"); // I get an exception here when I send a request to the server
resp = inFromServer.readLine();
if (!resp.isEmpty()) {
System.out.println(resp);
}
if (req.equals("exit")) {
System.exit(1);
}
}
}
}
Why do I get the exception that I indicated above when I resubmit the request to the TCP server and why is this exception not thrown when sending a second request to the HTTP server?
#Override
protected String getRequest(BufferedReader input) throws IOException {
return input.readLine();
}
#Override
protected void setResponse(BufferedWriter output, String request) throws IOException {
String result = serverCommandController.execute(RequestParser.tcpParserCommand(request));
output.write(result);
output.flush();
}
You are closing the client connection before the client is done. Try this in your Server class:
#Override
public void run()
{
try (BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream())); BufferedWriter output = new BufferedWriter(new PrintWriter(clientSocket.getOutputStream())))
{
while (clientSocket.isConnected())
{
String req = getRequest(reader);
setResponse(output, req);
}
}
catch (IOException e)
{
e.printStackTrace();
}
finally
{
try
{
clientSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Your server appears to close the socket after sending a response. After that, the client will not be able to send further requests without opening a new connection. Typically, the server allows the client to control the fate of the connection, so that the client can send multiple requests. Your client could send a "close" request to indicate to the server that the client intends to close the socket and does not expect a response.

What's causing java.net.SocketException: Connection reset after closing client?

I'm writing a server/client application for school.
Every time I close the client, the server throws 'java.net.SocketException: Connection reset'. I think, I have to close the socket in the client before closing the JavaFX-window, but where? Or what do you think?
I've seen a similar question, but I don't know how to implement it correctly in my programm.
Exception:
20:05:27.132 [Thread-2] ERROR OnlineBank - java.net.BindException: Address already in use: JVM_Bind
19:51:06.580 [Thread-1] ERROR ServerHandler - java.net.SocketException: Connection reset
19:51:06.580 [Thread-2] ERROR ServerHandler - java.net.SocketException: Connection reset
MyProgramm:
private MyProgramm() {
server = new MyServer(Constants.REMOTE_PORT);
try
server.start();
} catch (ClassNotFoundException | IOException e) {
logger.error(e);
}
}
MyServer:
public void start() throws ClassNotFoundException, IOException {
try {
serverSocket = new ServerSocket(this.port);
while (true) {
Socket client = serverSocket.accept();
logger.debug(getClass().getName() + " accepts");
Thread threadHandler = new Thread(new ServerHandler(client));
threadHandler.start();
}
} finally {
if (serverSocket != null) {
serverSocket.close();
}
}
}
ServerHandler:
#Override
public void run() {
try (InputStream in = clientSocket.getInputStream();
OutputStream out = clientSocket.getOutputStream();
ObjectInputStream oin = new ObjectInputStream(in);
ObjectOutputStream oos = new ObjectOutputStream(out)) {
while (true) {
try {
Object receivedObject = oin.readObject();
handleReceivedObject(oos, receivedObject);
} catch (ClassNotFoundException e) {
logger.error(e);
break;
}
}
} catch (IOException e) {
logger.error(e);
}
}
MainClient:
public class MainClient extends Application {
private static Client client;
public static void main(String[] args) {
launch(args);
try {
client = new Client();
} catch (IOException e) {
logger.error(e);
}
}
#Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("/welcome.fxml"));
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void stop() throws Exception {
super.stop();
// to avoid NullPointerException
if (Client != null && Client.getSocket() != null) {
Client.getSocket().close();
}
}
}
Client:
public class Client {
private Socket socket;
public Client(String remoteHost, int port) throws UnknownHostException, IOException {
if (getSocket() == null) {
socket = new Socket(remoteHost, port);
}
}
public Client() throws UnknownHostException, IOException {
this(Constants.REMOTE_HOST, Constants.REMOTE_PORT);
}
public Socket getSocket() {
return socket;
}
}
You are correct. You have to close the client socket properly before exiting the client. Otherwise the operating system may reset the connection instead of closing it. Not being an Android guy I cannot advise you where this closure should be placed.
Your server has a problem too. It needs to catch EOFException in the read loop and silently break. At present you aren't handling end of stream correctly: you will catch it via catch (EOFException ) and log it as an error, which it isn't really.

Java chat application only picking up some sent messages

I'm writing an all-in-one java chat program which will either act as a client or a server. I'm currently having this problem where, after the connection is established, the program only successfully recieves (or sends?) some of the messages. I've used a loop to spam through a load of junk and I've seen that the other end will only pick up some of the messages. I've never got a message to send manually.
Here is the code:
public class ConnectionThread implements Runnable {
private Connection c = Connection.getInstance();
private ChatInterface chatInterface;
private static ConnectionThread serverThread;
private ServerSocket serverSocket;
private Socket socket;
private ObjectInputStream dataIn;
private ObjectOutputStream dataOut;
public ConnectionThread() {}
public static synchronized ConnectionThread getInstance() {
if (serverThread == null) {
serverThread = new ConnectionThread();
}
return serverThread;
}
public void run() {
// If the programs role is server, set up the server
if (c.getRole() == ConnectionRole.SERVER) {
try {
setupServer();
waitForConnection();
setupStreams();
} catch (IOException e) {
e.printStackTrace();
}
do {
try {
chatInterface.addToChatHistory(dataIn.readUTF());
} catch (IOException e) {
e.printStackTrace();
}
} while (c.getRole() == ConnectionRole.SERVER);
}
// If the programs role is client, set up a connection to the server
if (c.getRole() == ConnectionRole.CLIENT) {
try {
setupClient();
setupStreams();
} catch (IOException e) {
e.printStackTrace();
}
do {
try {
chatInterface.addToChatHistory(dataIn.readUTF());
} catch (IOException e) {
e.printStackTrace();
}
} while (c.getRole() == ConnectionRole.CLIENT);
}
}
private void setupClient() throws IOException {
System.out.println("ATTEMPTING TO CONNECT...");
socket = new Socket("127.0.0.1", 8080);
System.out.println("CONNECTED!");
}
private void setupServer() throws IOException {
System.out.println("SETTING UP SERVER..");
serverSocket = new ServerSocket(8080, 1);
System.out.println("SERVER SETUP");
}
private void waitForConnection() throws IOException {
System.out.println("WAITING FOR A CONNECTION...");
socket = serverSocket.accept();
System.out.println("CONNECTION RECIEVED");
}
private void setupStreams() throws IOException {
System.out.println("SETTING UP STREAMS...");
dataOut = new ObjectOutputStream(socket.getOutputStream());
dataIn = new ObjectInputStream(socket.getInputStream());
chatInterface = ChatInterface.getInstance();
System.out.println("STREAMS SETUP");
}
public void sendMessage(String message) throws IOException {
System.out.println("SENDING MESSAGE...");
dataOut.writeUTF(message);
chatInterface.addToChatHistory(message);
System.out.println("MESSAGE SENT!");
}
}
Can anyone tell me why not all messages are being sent/picked up properly? I've been playing with it for quite a while now and I can't figure out why.
I found out after following EJP's recommendation to switch to DataInput/OutputStreams which worked straight away. Although I did need to be using ObjectInput/OutputStreams so I switched back. I found that I got the same issue again, until I switched to write/readObject instead of write/readUTF. If I cast the readObject to (String) it would then manage to receive every message.
So if anyone is having the same problem with ObjectInput/OutputStreams using write/readUTF try using write/readObject instead.

Categories

Resources