I'm writing a simple TCP client/server program pair in Java, and the server must disconnect if the client hasn't sent anything in 10 seconds. socket.setSoTimeout() gets me that, and the server disconnects just fine. The problem is - how can I get the client to determine if the server is closed? Currently I'm using DataOutputStream for writing to the server, and some answers here on SO suggest that writing to a closed socket will throw an IOException, but that doesn't happen.
What kind of writer object should I use to send arbitrary byte blocks to the server, that would throw an exception or otherwise indicate that the connection has been closed remotely?
Edit: here's the client code. This is a test function that reads one file from the file system and sends it to the server. It sends it in chunks, and pauses for some time between each chunk.
public static void sendFileWithTimeout(String file, String address, int dataPacketSize, int timeout) {
Socket connectionToServer = null;
DataOutputStream outStream = null;
FileInputStream inStream = null;
try {
connectionToServer = new Socket(address, 2233);
outStream = new DataOutputStream(connectionToServer.getOutputStream());
Path fileObject = Paths.get(file);
outStream.writeUTF(fileObject.getFileName().toString());
byte[] data = new byte[dataPacketSize];
inStream = new FileInputStream(fileObject.toFile());
boolean fileFinished = false;
while (!fileFinished) {
int bytesRead = inStream.read(data);
if (bytesRead == -1) {
fileFinished = true;
} else {
outStream.write(data, 0, bytesRead);
System.out.println("Thread " + Thread.currentThread().getName() + " wrote " + bytesRead + " bytes.");
Thread.sleep(timeout);
}
}
} catch (IOException | InterruptedException e) {
System.out.println("Something something.");
throw new RuntimeException("Problem sending data to server.", e);
} finally {
TCPUtil.silentCloseObject(inStream);
TCPUtil.silentCloseObject(outStream);
TCPUtil.silentCloseObject(connectionToServer);
}
}
I'd expect the outStream.write to throw an IOException when it tries to write to a closed server, but nothing.
I'd expect the outStream.write to throw an IOException when it tries to write to a closed server, but nothing.
It won't do that the first time, because of the socket send buffer. If you keep writing, it will eventually throw an IOException: 'connection reset'. If you don't have data to get to that point, you will never find out that the peer has closed.
I think you need to flush and close your stream after written like outStream.flush(); outStream.close(); inStream.close();
Remember ServerSocket.setSoTimeout() is different from client's function with same name.
For server, this function only throws SocketTimeoutException for you to catch it if timeout is expired, but the server socket still remains.
For client, setSoTimeout() relates to 'read timeout' for stream reading.
In your case, you must show your server code of closing the connected socket after catching SocketTimeoutException => ensure server closed the associated socket with a specified client. If done, at client side, your code line:
throw new RuntimeException("Problem sending data to server.", e);
will be called.
[Update]
I noticed that you stated to set timeout for the accepted socket at server side to 10 secs (=10,000 milliseconds); for that period, did your client complete all the file sending? if it did, never the exception occurs.
[Suggest]
for probing, just comment out your code of reading file content to send to server, and try replacing with several lines of writing to output stream:
outStream.writeUTF("ONE");
outStream.writeUTF("TWO");
outStream.writeUTF("TREE");
Then you can come to the conclusion.
Related
Here is the flow of my client/server.
Socket is created in main thread.
Socket passes to Thread 1.
Client sends data to server
Server responds to client
Server closes input stream, output stream, and socket by invoking close()
Socket returned to main thread, and then passed to Thread 2.
Client writes data to server - no exception, no errors, server gets no data
Client attempts to read data - no exceptions, no errors
How can I detect the problem that socket was closed?
try {
os = new DataOutputStream(this.socket.getOutputStream());
os.write(data);
os.flush();
System.out.println("Written " + data.length + " bytes");
} catch (IOException e) {
System.out.println("Client failed to write to stream");
System.out.println(e.getMessage());
e.printStackTrace();
}
The exception is never thrown. It says Written 60 bytes. Any ideas?
UPDATE
Here is the way that I read the response. I wait for data, read first 4 bytes (which gives the the length of response), and keep reading until I read the specified length. This loop never ends because no data ever comes in.
is = new DataInputStream(this.socket.getInputStream());
while(true){
while(is.available() > 0){
bos.write(is.read());
}
if(contentLength == 0 && bos.size() > 3){
byte[] bytes = bos.toByteArray();
byte[] size = Arrays.copyOf(bytes, 4);
contentLength = ByteBuffer.wrap(size).getInt();
}
if(bos.size() - 4 < contentLength){
continue;
}
break;
}
When the server closes its end of the TCP connection, it sends a FIN packet to tell the client. The client program sees this as the InputStream reaching the end. Also, if the client tries to write the server will send an RST packet to signal error. If the client program tries to write after RST was received, the API will throw a SocketException with the message "connection reset."
Your problem is with detecting the end of the input here:
while(is.available() > 0){
bos.write(is.read());
}
The available method probably doesn't do what you think it does. If you want to read 4 bytes, read 4 bytes:
byte[] bytes = new byte[4];
is.readFully(bytes); // throws EOFException on end of input
It says that it wrote 60 bytes because it did. The server just isn't listening anymore. You need to get the input stream to see if anything is there. If nothing comes back, then you know that the connection didn't work.
UPDATE
Use a timer to determine if the server is responding.
Long currenttime = System.currentTimeMillis();
while(System.currentTimeMillis() - currentTime < x){ //x = miliseconds you want to wait
(try to read from server)
}
This way if it takes longer than x seconds, it will time out and you can do some error catching after the while loop
UPDATE I've found that this error is related to the GZIP streams. If I remove them and just use Object streams rather than GZIP wrapped with Object streams then my issues are resolved, no exception. I have no idea why this is, if anyone can help that would be great.
I also noted while using the GZIP that the error would be very random. E.g it seemed to depend a lot on the data within the object that I was sending across the socket. Alter the object data and it would sometimes solve the issue. For example I had a user object which contained String values such as, first name, surname, phone number. If they were all set I was getting the below issue, however if I cleared them all to be empty String values then I wouldn't get the below exception. It's very bizarre to be honest
I have a client/server socket which sends object via GZIP streams. This has worked without issue in the past. However now I am seeing connection reset when sending certain data from the server back to the client.
The client connects to the server and sends a request, to which the server will reply and send back some data. I believe the error is from the server as the connection reset exception is presented on the client side.
Here is a snippet of the exception
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at com.sun.net.ssl.internal.ssl.InputRecord.readFully(InputRecord.java:293)
at com.sun.net.ssl.internal.ssl.InputRecord.read(InputRecord.java:331)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:863)
at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readDataRecord(SSLSocketImpl.java:820)
at com.sun.net.ssl.internal.ssl.AppInputStream.read(AppInputStream.java:75)
It's a very strange issue because the same socket implementation is used for all client / server communication and in our test environment everything works fine. Also the same code is used successfully before the exception occurs to collect some data from the server when the client loads the application on startup.
The above information leads me to believe there could be an issue with the specific data that is being passed, although the client & server both present no exception other than the connection reset.
Looking at netstat ( netstat -anp ) while debugging I can see successful actions result in a socket in the state of "CLOSE_WAIT", however unsuccessful ones the socket just seems to disappear all together, it's not there in any state. I also note that there is a lot of RST when the connections are finished, even for sucessful cases where I don't get connection reset exception. My TCP knowledge isn't great, but I would have thought a clean connection would end with FIN rather than getting RST?
Here is an example of the code
Client:
ObjectOutputStream out = null;
ObjectInputStream ois = null;
SSLSocketFactory sf = AdminClientApplet.getSSLContext().getSocketFactory();
Socket socket = null;
DataResponse dataRes = null;
try
{
socket = sf.createSocket( server.getHost(), server.getPort() );
// Need to connect to server and send request type,
// ie what we are requesting to be sent to us
GZIPOutputStream gZipOut = new GZIPOutputStream(socket.getOutputStream());
out = new ObjectOutputStream(gZipOut);
// write our request
out.writeObject( dataReq );
out.flush();
gZipOut.finish();
InputStream in = socket.getInputStream();
GZIPInputStream gZipIn = new GZIPInputStream(in, 65536);
ois = new ObjectInputStream(gZipIn);
// read our response
dataRes = ( DataResponse )ois.readObject();
Log.CSSO.debug("Read object " + dataRes );
}
catch (IOException ie)
{
Log.GUIP.error("IOException communicating with Admin Server on "+server, ie);
}
catch ( Exception e)
{
Log.GUIP.error("Unexpected exception communicating with Admin Server on "+server, e);
}
catch (Throwable t)
{
Log.GUIP.error("Unexpected exception communicating with Admin Server on "+server, t);
}
finally
{
// now close the connection gracefully
CSSO.debug("closing socket");
try
{
if ( out != null )
out.close();
if ( ois != null )
ois.close();
if ( socket != null )
socket.close();
}
catch ( Exception e )
{
Log.CSSO.error( "Error closing socket connection during getDataFromServer()", e );
}
}
The server has already read the 'request' at this point, so this is just the part that returns the requested data to the client.
Server:
Socket socket = null;
try
{
socket = request.getSocket();
socket.setTcpNoDelay(true);
Log.CSSO.debug("Opening a response output stream to socket "+socket );
gZipOut = new GZIPOutputStream(socket.getOutputStream(), 65536 );
out = new ObjectOutputStream(gZipOut);
// the actual 'data' we are going to return
obj = getObject();
Log.CSSO.debug("About to write " + obj + " to socket" + socket.getRemoteSocketAddress() );
out.writeObject( obj );
if (Log.CSSO.isDebugEnabled())
{
Log.CSSO.debug("Wrote DataResponse to socket " + obj );
}
out.flush();
gZipOut.finish();
}
catch (IOException ie)
{
Log.CSSO.error("IOException caught sending data to client", ie);
}
catch (Exception e)
{
Log.CSSO.error("Unexpected exception caught sending data to client", e);
}
finally
{
Log.CSSO.debug( "Closing socket to " + socket.getRemoteSocketAddress() );
try
{
if ( out != null ) out.close();
if ( socket != null ) socket.close();
}
catch ( IOException e )
{
Log.CSSO.error("Unexpected exception caught closing socket", e );
}
}
Log.FLOW.debug("< run");
When on debug logging the server runs all the way through to completion, without any exceptions ( so "< run" is written in the logs ). However the client errors at
ois = new ObjectInputStream(gZipIn);
The other item worth noting is that the live system, where the exception occours is running linux ( Centos ), where as I'm not able to replicate the exception on windows and it doesn't happen on Linux Mint either. I don't expect this would be the cause but just thought I should mention it.
Any help much appreciated as I'm lost as to the cause of the issue here.
I am trying to implement an HTTP Server using Sockets. If the Client (For example a browser) requests a directory the server displays a list of available files. The problem arises when the client is requesting a file. I get the following error:
java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:113)
at java.net.SocketOutputStream.write(SocketOutputStream.java:159)
at cf.charly1811.java.web.RequestHandler.writeFile(RequestHandler.java:152)
at cf.charly1811.java.web.RequestHandler.processRequest(RequestHandler.java:139)
at cf.charly1811.java.web.RequestHandler.handleRequest(RequestHandler.java:110)
at cf.charly1811.java.web.RequestHandler.run(RequestHandler.java:86)
at java.lang.Thread.run(Thread.java:745)
The stacktrace shows that the problem is coming from the writeFile() methods:
private void writeFile(File request) throws IOException
{
InputStream byteReader = new BufferedInputStream(new FileInputStream(request));
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = byteReader.read(buffer)) != -1)
{
outputStream.write(buffer, 0, bytesRead);
}
byteReader.close();
}
But I can't figure out what's wrong.
Can you help me?
EDIT
Thanks everyone for your answers. After I read your answers I understood that the problem was that the Socket when an error occured. Here's was my wrong code:
// Method to process a single request
handleRequest() throw IOException
{
// process here
// if the client request a file
writeFile();
// close socket when the request is processed
}
// The method is called
public run()
{
try{
// If an error occurs the try/catch won't be called because it is implemented outside the loop. So when an IOException occurs, the loop just stop and exit the program
while(true)
{
handleRequest();
}
}
catch(IOException e) {
// Handle exception here
}
}
And my new code was looking like this:
// Method to process a single request
handleRequest()
{
try {
// process here
// if the client request a file
writeFile();
// close socket when the request is processed
}
// If this exception occurs the catch() method will be called
catch(IOException e)
{
// handle exception here
}
}
// The method is called
public run()
{
while(true)
{
handleRequest();
}
}
}
It is possible for the TCP socket to be "closing" and your code to not have yet been notified.
Here is a animation for the life cycle. http://tcp.cs.st-andrews.ac.uk/index.shtml?page=connection_lifecycle
Basically, the connection was closed by the client. You already have throws IOException and SocketException extends IOException. This is working just fine. You just need to properly handle IOException because it is a normal part of the api.
EDIT: The RST packet occurs when a packet is received on a socket which does not exist or was closed. There is no difference to your application. Depending on the implementation the reset state may stick and closed will never officially occur.
This problem is usually caused by writing to a connection that had already been closed by the peer. In this case it could indicate that the user cancelled the download for example.
I face this problem but resolution is very simple.
I am writing the 1 MB file in 1024 Byte Buffer causing this issue.
To Understand refer code before and After Fix.
Code with Excepion
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
while (fis.read(buffer) > 0) {
dos.write(buffer);
}
After Fixes:
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[102400];
while (fis.read(buffer) > 0) {
dos.write(buffer);
}
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
java.net.SocketException: Software caused connection abort: recv failed
I'm trying to write a client server pair where the connection is live all day and the client waits for the server to send a message. The steps are:
Server opens port and listens for connection
Client connects in and waits for data
Some time later (maybe hours) the server sends data to the client
Client processes data and returns it to the server
Repeat steps 3 and 4
I can get steps 1-4 working, however if I try to repeat step 3 I get the error in the title.
This is my method on the client side:
private static void waitForInput(SSLSocket sslsocket) throws IOException {
do {
try {
ObjectInputStream ois = new ObjectInputStream(sslsocket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(sslsocket.getOutputStream());
Object o = (Object) (ois.readObject());
// excluded code to process data
oos.flush();
oos.writeObject(o);
oos.reset();
}
catch(ClassNotFoundException e){
System.err.println(e.getMessage());
}
} while ( true );
}
The code fails on the 4th line, The first time around it blocks and waits until I get the next bit of data, but it doesn't work twice. What am I doing wrong?
Connection abort IOException is thrown when you are waiting to read from a socket that has been closed at the other end, check to see your server side code , if you are not accidentally closing the socket.
Also the server side code could be uploaded for deeper analysis, also try posting the stack trace, it will help analyzing.
You could move the declaration for ois and oos out of the do ... while loop, since there is no need to redeclare them everytime, might need a try ... catch around that.
private static void waitForInput(SSLSocket sslsocket) throws IOException {
ObjectInputStream ois = new ObjectInputStream(sslsocket.getInputStream());
ObjectOutputStream oos = new ObjectOutputStream(sslsocket.getOutputStream());
do {
try {
Object o = (Object) (ois.readObject());
// excluded code to process data
oos.writeObject(o);
oos.flush();
}
catch(ClassNotFoundException e){
System.err.println(e.getMessage());
}
} while ( true );
}
And I have removed the oos.reset(); and moved the oos.flush();
I believe that the problem is the oos.reset(); and i would never reset a connection that is supposed to be persistent for hours, or, at least part of it.
Besides there is already a ois for that connection and you don't need two of them.
I have a Java TCP server which, when a client connects to it, outputs a message to the client every 30 seconds. It is a strict requirement that the client does not send any messages to the server, and that the server does not send any data other than the 30-second interval messages to the client.
When I disconnect the client, the server will not realise this until the next time it tries to write to the client. So it can take up to 30 seconds for the server to recognise the disconnect.
What I want to do is check for the disconnect every few seconds without having to wait, but I am not sure how to do this given that a) the server does not receive from the client and b) the server cannot send any other data. Would anyone please be able to shed some light on this? Thanks.
Even though your server doesn't "receive" from the client, a non-blocking read on the client socket will tell you that either there's nothing to be read (as you expect), or that the client has disconnected.
If you're using NIO you can simply use a non-blocking Selector loop (with non-blocking sockets) and only write on your 30 second marks. If a SelectionKey is readable and the read on the SocketChannel returns -1 you know the client has disconnected.
EDIT: Another approach with blocking is simply to select with a 30 second timeout. Any client disconnects will cause the select to return and you'll know which ones those are via the read set. The additional thing you'd need to do there is track how long you were blocked in the select to figure out when to do your writes on the 30 second mark (Setting the timeout for the next select to the delta).
Big Edit: After talking to Myn below, offering complete example:
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(4444);
} catch (IOException e) {
System.err.println("Could not listen on port: 4444.");
System.exit(1);
}
Socket clientSocket = null;
try {
clientSocket = serverSocket.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
System.exit(1);
}
// Set a 1 second timeout on the socket
clientSocket.setSoTimeout(1000);
PrintWriter out = new PrintWriter(clientSocket.getOutputStream(), true);
BufferedReader in = new BufferedReader(
new InputStreamReader(
clientSocket.getInputStream()));
long myNextOutputTime = System.currentTimeMillis() + 30000;
String inputLine = null;
boolean connected = true;
while (connected)
{
try {
inputLine = in.readLine();
if (inputLine == null)
{
System.out.println("Client Disconnected!");
connected = false;
}
}
catch(java.net.SocketTimeoutException e)
{
System.out.println("Timed out trying to read from socket");
}
if (connected && (System.currentTimeMillis() - myNextOutputTime > 0))
{
out.println("My Message to the client");
myNextOutputTime += 30000;
}
}
out.close();
in.close();
clientSocket.close();
serverSocket.close();
}
Worth noting here is that the PrintWriter really moves you far away from the actual socket, and you're not going to catch the socket disconnect on the write (It will never throw an exception, you have to manually check it with checkError()) You could change to using a BufferedWriter instead (requires using flush() to push the output) and handling it like the BufferedReader to catch a disco on the write.
If you are managing multiple clients then I guess you would be using Non-Blocking sockets (If not then consider using Non-Blocking). You can use Selector to monitor all the connected sockets to check if they are readable or writeable or there is some Error on that socket. When some client disconnects, your Selector will mark that socket and will return.
For more help google "Socket Select function"