Why does the socket close when I try to write to the output stream?
The stacktrace:
Exception in thread "main" java.lang.RuntimeException: java.net.SocketException: Socket is closed
at chatx.server.handler.ExceptionHandler.handle(ExceptionHandler.java:14)
at chatx.server.handler.ExceptionHandler.handle(ExceptionHandler.java:6)
at chatx.server.Client.authenticate(Client.java:75)
at chatx.server.handler.SocketHandler.handle(SocketHandler.java:23)
at chatx.server.handler.SocketHandler.handle(SocketHandler.java:12)
at chatx.server.Server.listen(Server.java:117)
at chatx.server.Server.start(Server.java:61)
at chatx.server.Main.main(Main.java:30)
Caused by: java.net.SocketException: Socket is closed
at java.base/java.net.Socket.getInputStream(Socket.java:905)
at chatx.server.Client.authenticate(Client.java:65)
... 5 more
The pre-authentication phase:
Client client = (Client) Optional.ofNullable(clientManager.getClient(socket.getInetAddress())).orElse(clientManager.addClient(new Client(socket)));
client.sendPacket(new PacketAuthentication(client.getUsername(), client.getPassword().toCharArray()));
if (client.authenticate()) {
System.out.printf("[Address: %s] Authenticated as %s.\n", client.getAddress(), client.getName());
client.start();
} else {
client.interrupt();
clientManager.removeClient(client);
System.out.printf("[Address: %s] Failed to authenticate.\n", client.getAddress());
}
The authentication phase:
try {
JsonObject o = new GsonBuilder().create().fromJson(new String(socket.getInputStream().readAllBytes()), JsonObject.class);
if (o.has("packet_id") && o.get("packet_id").getAsInt() == PacketAuthentication.ID) {
JsonObject data = o.getAsJsonObject("data");
String username = data.get("username").getAsString();
String password = data.get("password").getAsString();
return this.username.equals(username) && this.password.equals(password);
}
} catch (IOException ex) {
Server.getInstance().getExceptionHandler().handle(ex);
}
The client-side authentication phase:
IClient client = new Client(new Socket("127.0.0.1", 8888));
client.sendPacket(new PacketAuthentication("Dummy", "Dummy123".toCharArray()));
The exception occurs in the authentication phase when socket.getInputStream() is called.
The idea was to let the client send an authentication packet on login and verify the information on server-side.
Edit:
I might have found the issue.
I am using a try-with-resources when writing to the OutputStream and I just realise that try-with-resources let the OutputStream close, thanks to #MousaHalaseh
But now I am getting another exception about 'Connection reset':
Exception in thread "main" java.lang.RuntimeException: java.net.SocketException: Connection reset
at chatx.server.handler.ExceptionHandler.handle(ExceptionHandler.java:14)
at chatx.server.handler.ExceptionHandler.handle(ExceptionHandler.java:6)
at chatx.server.Client.authenticate(Client.java:86)
at chatx.server.handler.SocketHandler.handle(SocketHandler.java:23)
at chatx.server.handler.SocketHandler.handle(SocketHandler.java:12)
at chatx.server.Server.listen(Server.java:117)
at chatx.server.Server.start(Server.java:61)
at chatx.server.Main.main(Main.java:28)
Caused by: java.net.SocketException: Connection reset
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:210)
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.base/java.io.InputStream.readAllBytes(InputStream.java:238)
at chatx.server.Client.authenticate(Client.java:76)
... 5 more
Edit 2:
Fixed the issue in Edit 1, by closing one end of the outputstream.
the error is pretty clear Socket is closed, things that might help troubleshoot this Exception:
Make sure you're not using socket.close(); in the client side.
You're not closing any of the input or output streams or even shutting down the input/output, as from the documents
Closing the returned InputStream will close the associated socket.
Closing the returned OutputStream will close the associated socket.
Your connection does not get timed out.
You do have a valid TCP connection in your machine.
Edit:
java.net.SocketException: Connection reset generally means that one end of the stream is closed, which you said that yourself
Fixed the issue in Edit 1, by closing one end of the outputstream.
Keep the output stream open, and you may have to add:
socket.setKeepAlive(true);
hope things work out for you.
Related
Not able to detect a socket close. Not receiving -1 when reading with inputStream. I am thinking about disconnecting in case of SocketTimeoutException and trying to connect the socket again. How feasible would that be?
socket.setSoTimeout(100);
InputStream dis = socket.getInputStream();
int count =0;
try {
LogManager.logInfo("Inside read thread before reading");
count = dis.read(buffer); // not receiving -1 in case of socket close
} catch (SocketTimeoutException e) {
LogManager.logError("Socket timedout",e);
// should i try to reconnect to socket here
}
Not able to detect a socket close.
You haven't closed the socket, so there is nothing to detect. What you no doubt mean is 'not able to detect connection close', which is signalled by read() returning -1, readLine() returning null, or readXXX() throwing EOFException for any other XXX. I don't see any code here that tests this.
Not receiving -1 when reading with inputStream.
If the socket was closed you would get SocketException: socket closed. If the connection was closed you would get the behaviour described above.
I am thinking about disconnecting in case of SocketTimeoutException
There is no 'disconnection in case of SocketTimeoutException'.
and trying to connect the socket again.
You can't reconnect TCP sockets. You must close the current one and create a new one.
How feasible would that be?
Not in the slightest.
// not receiving -1 in case of socket close
See above re 'socket close'. If you're not receiving -1 from read() it is because there is no connection socket close.
When you receive a SocketTimeoutException, the socket is not closed, and neither is the connection, and there is no particular reason to close either of them. All it means is that no data arrived from the peer within the timeout you specified. Possibly the timeout is too short; possibly the peer is misbehaving. It is up to your application to decide which, based on the application protocol, expected service times, network latencies, ...
And 100ms is ridiculously short for a read timeout. It should be measured in seconds or tens of seconds.
I have a problem with handling socket in java.
I am running a TCP server with multiple client connections.
For performance reason, I used a simple thread pool to handle packets.
Please see code below
public enum LazyWorkCenter {
instance;
LazyWorkCenter() {
lazyWorker = new NamedThreadPoolExecutor(3,3, 0L,TimeUnit.MILLISECONDS, "LazyWorker");
}
private ExecutorService lazyWorker ;
public void executeLazy(Runnable lazyTask) {
lazyWorker.execute(lazyTask);
}
}
public class TcpServerForClient {
DataOutputStream out = null;
DataInputStream in = null;
public void onConnect(ServerSocket socket) throws IOException {
Socket client = server.accept();
client.setSoTimeout(1000 * 10);
out = new DataOutputStream(client.getOutputStream());
in = new DataInputStream(client.getInputStream());
}
public void sendToClient( byte[] buffer) {
Runnable lazy = () -> {
out.write(buffer);
out.flush();
};
LazyWorkCenter.instance.executeLazy(lazy);
}
}
multiple threads might access to sendToClient.
this code usually works fine, but some times(probably when flooding?) It hangs without any Exception until I shutdown client connection manually.
After I shutdown client connection, then I got tons of exception flooding SocketException: Broken pipe from out.write(buffer);
7053555 [LazyWorker-1] 09:57:35.268 [ERROR] [LazyWorker-1#c.t.s.TcpServerForClient:44] - error found
java.net.SocketException: Broken pipe
at java.net.SocketOutputStream.socketWrite0(Native Method) ~[na:1.8.0_91]
at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:109) ~[na:1.8.0_91]
at java.net.SocketOutputStream.write(SocketOutputStream.java:153) ~[na:1.8.0_91]
at java.io.DataOutputStream.write(DataOutputStream.java:107) ~[na:1.8.0_91]
at java.io.FilterOutputStream.write(FilterOutputStream.java:97) ~[na:1.8.0_91]
My major Problem is that server could hang until client quit connection.
I guess If I can set a time out for writing then Server might close out connection by itself but I could not find appropriate way for this.
I have tried socket.setSoTimeOut(); as well but it seems only for receiving data from client.
Any hint or advice will be very appreciated.
Please let me know If more code or information is needed to figure this out.
Thanks in advance.
How can I set Socket write timout in java?
You can't. There is no socket write timeout in Java. Unless you make the hyperjump to NIO, non-blocking mode, Selectors, etc.
I got tons of exception flooding SocketException: Broken pipe from out.write(buffer);
You should only get one. You should close the socket when you get this exception.
ERROR GServerHandler - java.io.IOException: Connection reset by peer
java.io.IOException: Connection reset by peer
at sun.nio.ch.FileDispatcher.read0(Native Method)
at sun.nio.ch.SocketDispatcher.read(Unknown Source)
at sun.nio.ch.IOUtil.readIntoNativeBuffer(Unknown Source)
at sun.nio.ch.IOUtil.read(Unknown Source)
at sun.nio.ch.SocketChannelImpl.read(Unknown Source)
at org.jboss.netty.channel.socket.nio.NioWorker.read(NioWorker.java:323)
at org.jboss.netty.channel.socket.nio.NioWorker.processSelectedKeys(NioWorker.java:282)
at org.jboss.netty.channel.socket.nio.NioWorker.run(NioWorker.java:202)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
This log is from a game server implemented using netty. What can cause this exception ?
java.io.IOException: Connection reset by peer
The other side has abruptly aborted the connection in midst of a transaction. That can have many causes which are not controllable from the server side on. E.g. the enduser decided to shutdown the client or change the server abruptly while still interacting with your server, or the client program has crashed, or the enduser's internet connection went down, or the enduser's machine crashed, etc, etc.
To expand on BalusC's answer, any scenario where the sender continues to write after the peer has stopped reading and closed its socket will produce this exception, as will the peer closing while it still had unread data in its own socket receive buffer. In other words, an application protocol error. For example, if you write something to the peer that the peer doesn't understand, and then it closes its socket in protest, and you then continue to write, the peer's TCP stack will issue an RST, which results in this exception and message at the sender.
java.io.IOException in Netty means your game server tries to send data to a client, but that client has closed connection to your server.
And that exception is not the only one! There're several others. See BadClientSilencer in Xitrum. I had to add that to prevent those errors from messing my log file.
java.io.IOException: Connection reset by peer
In my case, the problem was with PUT requests (GET and POST were passing successfully).
Communication went through VPN tunnel and ssh connection. And there was a firewall with default restrictions on PUT requests... PUT requests haven't been passing throughout, to the server...
Problem was solved after exception was added to the firewall for my IP address.
For me useful code witch help me was http://rox-xmlrpc.sourceforge.net/niotut/src/NioServer.java
// The remote forcibly closed the connection, cancel
// the selection key and close the channel.
private void read(SelectionKey key) throws IOException {
SocketChannel socketChannel = (SocketChannel) key.channel();
// Clear out our read buffer so it's ready for new data
this.readBuffer.clear();
// Attempt to read off the channel
int numRead;
try {
numRead = socketChannel.read(this.readBuffer);
} catch (IOException e) {
// The remote forcibly closed the connection, cancel
// the selection key and close the channel.
key.cancel();
socketChannel.close();
return;
}
if (numRead == -1) {
// Remote entity shut the socket down cleanly. Do the
// same from our end and cancel the channel.
key.channel().close();
key.cancel();
return;
}
...
There are lot of factors , first see whether server returns the result, then check between server and client.
rectify them from server side first,then check the writing condition between server and client !
server side rectify the time outs between the datalayer and server
from client side rectify the time out and number of available connections !
It can also mean that the server is completely inaccessible - I was getting this when trying to hit a server that was offline
My client was configured to connect to localhost:3000, but no server was running on that port.
I have a bufferedreader and for some reason it wont read the text from the print stream I am sending from my client. This is the point at which it fails every time the line = in.readline
Also I have checked and the server is connected.
This is the error
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(SocketInputStream.java:168)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
at java.io.InputStreamReader.read(InputStreamReader.java:167)
at java.io.BufferedReader.fill(BufferedReader.java:136)
at java.io.BufferedReader.readLine(BufferedReader.java:299)
at java.io.BufferedReader.readLine(BufferedReader.java:362)
at Server.ServerListener$getXML.run(ServerListener.java:82)
at java.lang.Thread.run(Thread.java:662)
Thanks in advance
BufferedReader in = new BufferedReader(new InputStreamReader(server.getInputStream()));
//PrintStream out = new PrintStream(server.getOutputStream());
System.out.println("Start");
//read the xml
boolean connected = server.isConnected();
System.out.println("xml: "+ connected);
line = in.readLine();
System.out.println("Postread");
while ((line = in.readLine()) != null) {
System.out.println("while1");
xml = xml + line;
System.out.println("while2");
}`
isConnected() tells you whether your socket is connected to the connection, not whether the connection is still connected to the peer. Obviously you aren't still connected at all. 'Connection reset' has several possible causes: you wrote to a connection that had already been closed by the other end (application protocol error); the other end aborted the connection; the local TCP stack has encountered network errors sending and has given up. First of those is then most likely suspect. And don't use PrintStreams/Writers across the network, as they swallow exceptions you need to know about. And you are throwing away a line of data with the first readLine() call: remove it and just leave the one in the loop.
I found the same problem in this post, but i think it wasn't solved.
i'm going to be brief, this is my code:
try {
Socket pacConx = new Socket(ip, Integer.parseInt(port));
DataInputStream dataIn = new DataInputStream(pacConx.getInputStream());
DataOutputStream dataOut = new DataOutputStream(pacConx.getOutputStream());
while(){...}
} catch (IOException e) {
logger.fatal("error", e);
}finally{
if (dataIn != null) {
dataIn.close();
}
if (dataOut != null) {
dataOut.close();
}
if (pacConx != null) {
pacConx.close();
}
}
First, i connect to the server using the code above, and it succeed.
But, when i try to REconnect to the same server and port after a while, i cannot reconnect.
Apparently the first socket is still "alive" in the serverSide.
is the a solution to my peoblem ?
Is there a way that i can close the other "alive" socket ?
Try
...
dataOut.flush();
dataOut.close();
...
Paste error message or/and full stack trace.
You need to initiate an orderly disconnect. After calling flush on the streams, and before calling close on the socket, add this:
pacConx.shutdownInput();
pacConx.shutdownOutput();
That tells the remote end you're finished and allows it to dismantle the port without waiting to make sure there isn't data still in transit.
For about 2-4 minutes after you close the socket it will hang in "CLOSE_WAIT" state on the server. This is a normal part of the TCP/IP protocol to handle delayed packets still wandering around in the network.
This should be handled by your server code. Is it unbinding its listen socket while handling a request and trying to re-establish it after the close? If so, it should either leave the listen up during processing or re-establish it with a SO_REUSEADDR option.