I want to detect a server-sided socket close (closed by socket.setSoTimeout) by sending data from the client Socket OutputStream (socket.getOutputStream().write(42)). If the Socket is closed on the server-side this should cause an Exception. But it only throws an Exception if I send data twice:
private boolean sendTest() {
try {
System.out.print("connection...");
socket.getOutputStream().write(42); //Sending "*"
socket.getOutputStream().write(42); //not working without this line
System.out.println("ok");
return true;
} catch (IOException e) {
System.out.println("error...disconnecting socket");
disconnect();
return false;
}
}
How can you explain this behaviour?
K here's the explanation:
You're sending the first byte to the server. Server gets it, and then closes the socket. Then, on THE NEXT WRITE, you get an IOException, since the socket connection is closed.
Related
I have a server and a client set up in this way. I can't find the cause of the EOFException, because it happens randomly. It throws the following exception every time a client connects, but I can't figure out the source of it. It always occurs before it reads what the client has sent. The exception always is at this line:
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Here is the exception:
java.io.EOFException
at java.base/java.io.ObjectInputStream$PeekInputStream.readFully(ObjectInputStream.java:2860)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.readShort(ObjectInputStream.java:3355)
at java.base/java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:939)
at java.base/java.io.ObjectInputStream.<init>(ObjectInputStream.java:381)
at com.denesgarda.Socketeer.data.End$3.run(End.java:62)
at com.denesgarda.Socketeer.data.End$3.run(End.java:76)
at com.denesgarda.Socketeer.data.End$3.run(End.java:76)
at com.denesgarda.Socketeer.data.End.listen(End.java:83)
at Server.<init>(Server.java:10)
at SStart.main(SStart.java:5)
Here is my server code:
if(listener == null) this.voidListener();
ServerSocket serverSocket = new ServerSocket(port);
End THIS = this;
TimerTask timerTask = new TimerTask() {
#Override
public void run() {
try {
Socket socket = serverSocket.accept();
socket.setSoTimeout(10000);
Connection connection = new Connection(THIS, new End((((InetSocketAddress) socket.getRemoteSocketAddress()).getAddress()).toString().replace("/","")), port, listener);
try {
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
Object o = objectInputStream.readObject();
if (o.equals("01101100 01101001 01110011 01110100 01100101 01101110 00100000 01110011 01110100 01100001 01110010 01110100")) {
listener.event(new ConnectionEvent(connection));
listener.event(new ConnectionSuccessfulEvent(connection));
}
else {
listener.event(new ReceivedEvent(connection, o));
}
socket.close();
}
catch(EOFException e) {
e.printStackTrace();
}
this.run();
}
catch(Exception e) {
e.printStackTrace();
}
}
};
timerTask.run();
Here is my client code:
if(listener == null) this.voidListener();
Socket socket = new Socket(address, port);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
send("Message");
public void send(Object object) throws IOException {
Socket socket = new Socket(THAT.getAddress(), this.port);
OutputStream outputStream = socket.getOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
objectOutputStream.writeObject(object);
socket.close();
}
What I've Tried
I've tried to fix this issue many times before. I tried to create object output streams. I've switched the order that I initialize the object input stream and object output stream. This is so that the server doesn't get frozen in a deadlock with the client. I have no idea what could be causing this error.
I think I know what is going on here, but I can't be certain because your code is fragmentary, and the symptoms are not well characterized. (The exceptions are unlikely to really be random, for example.)
First there is one indisputable fact. A one side of a connection sees an EOFException because the other side has closed the network connection. That's what that exception means.
In your case, the server gets the exception in the ObjectInputStream constructor because the constructor attempts to read an object stream header that the client side never sends ... on that connection.
Now, the theory. I think I know why. Here is the relevant part of your code (with some bits snipped out for brevity).
Socket socket = new Socket(address, port);
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
[...]
socket.close();
[...]
}
});
send("Message");
public void send(Object object) throws IOException {
Socket socket = new Socket(THAT.getAddress(), this.port);
[...]
}
Notice that there are two sockets! The first one is created and passed to the shutdown hook. The second one is created and used within send and then closed.
I think the problem is the first Socket. When that is created, it establishes a connection to the server. The server code will accept it and then attempt to read. The read will block ... since the client side hasn't written anything to that socket. The client will then call send which opens and uses a different Socket.
Eventually, the client application exits.
When it exits, the shutdown hook closes the first socket. That causes the server side to see the end of stream ... and triggers the EOFException.
So how to fix this?
It rather depends on the "big picture". Is the real client sending a single message to the server, or does it need to reuse the socket to send multiple messages?
Assuming the former, the solution is simple:
Get rid of the code that creates a socket and passes it to a shutdown hook. As you have written it, it serves no useful purpose.
Rewrite the send method to use try with resources; e.g.
public void send(Object object) throws IOException {
try (Socket socket = new Socket(THAT.getAddress(), this.port);
OutputStream os = socket.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os)) {
oos.writeObject(object);
}
}
Note that the above will automatically close the 3 resources in the correct order.
I have a TCP Server written in java. I am trying to connect to it via a TCP client socket written in dartlang but the client written in dartlang times out almost immediately after the initial connection (my five second timeout set in the java code). I was able to send a message to the dart client in a test immediately after it connected but it soon timed out. However the data in the dartlang '{"packet_id":1}' never gets received by the server.
I tried writing a test server in dartlang and it was able to connect and send/receive messages without any issues.
Dart Client:
import 'dart:io';
import 'dart:async';
main(List<String> arguments) {
Future<Socket> future = Socket.connect('localhost', 12345);
future.then((client) {
print('connected to server!');
client.handleError((data){
print(data);
});
client.listen(
(data) {
print(new String.fromCharCodes(data));
},
onDone:(){
print("Done");},
onError: (error) {
print(error);
}
);
String requestHalls = '{"packet_id":1}';
client.write(requestHalls);
}).catchError(() {print('Error connecting');});
print('Hello world: ${dart_test.calculate()}!');
}
My Java client connects to the Java Server socket just fine.
EDIT: adding java code
creating the serversocket.
#Override
public void run() {
// Create Server Socket for clients to connect to
try {
// load data from config manager
ConfigManager config = HDAServer.getConfigManager();
int port = config.getServerPort();
String ip = config.getServerURL();
Inet4Address inet4 = (Inet4Address) Inet4Address.getByName(ip); // this allows for binding to domain name or ipv4 address
HDAServer.getLogger().info(String.format("Opening Server Socket at address(%s)= %s:%s", ip, inet4.getHostAddress(), port));
// attempt to bind
serverSocket = new ServerSocket(config.getServerPort(), 50, inet4);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// wait for incoming client connections
waitForConnections();
}
/**
* Method that waits for incoming connections, adds the connection to a new pool, and creates a
* new thread for the connection to run on.
*/
private void waitForConnections() {
// loop through waiting for incoming connections until server shuts down
while (!shutdown) {
Socket socket = null;
try {
// blocks thread waiting for a connection
socket = serverSocket.accept();
} catch (IOException e) {
if (e.getMessage().equals("socket closed")) {
HDAServer.getLogger().info("Shutting Down Server Socket");
continue;// skip to while check
} else {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// create our connection class, start it in a new thread, and add it to our connection list
HDAServerConnection newConn = new HDAServerConnection(socket);
new Thread(newConn).start();
connections.add(newConn);
HDAServer.getLogger().info(String.format("Client connected from: %1s", newConn.getRemoteIP()));
// reap dead connections
this.reapDeadConnections();
}
}
Servers "Client" HDAConnection class:
protected Socket socket;
protected DataInputStream inputStream;
protected DataOutputStream outputStream;
private boolean shutdown = false;
public HDAConnection(Socket socket) {
this.socket = socket;
// configure socket
try {
socket.setKeepAlive(true);
socket.setSoTimeout(5000);
socket.setTcpNoDelay(true);
} catch (SocketException ex) {
AbstractHDALogger.get().severe("Error configuring Socket Connection.", ex);
}
// create input/output stream for handling data
try {
inputStream = new DataInputStream(socket.getInputStream());
outputStream = new DataOutputStream(socket.getOutputStream());
} catch (IOException ex) {
AbstractHDALogger.get().severe("Error creating input/output streams.", ex);
}
}
code that is listening for a message over the stream.
String response = null;
try {
response = new BufferedReader(new InputStreamReader(inputStream)).readLine();
} catch(SocketTimeoutException ste) {
shutdown();
AbstractHDALogger.get().severe(String.format("Socket Timed out(%s), closing Connection", this.getRemoteIP()), ste);
// TODO: handle exception
} catch (IOException e) {
// TODO Make this better?
// IO Exception probably means client disconnected, so we should terminate.
if (e.getMessage().equals("Connection reset")) {
shutdown();
AbstractHDALogger.get().info(String.format("Client Connection Disconnected(%s). Closing connection.", this.getRemoteIP()));
} else {
shutdown();
AbstractHDALogger.get().severe(String.format("Connection Error(%s), closing Connection", this.getRemoteIP()), e);
}
return null;
}
The socket is timing out on the Java Server because the dartlang client is never writing a newline at the end of its message and the Java Server is using the readline method to read. This function will only return when it reads a new line character. After reading the initial message from the dartlang client the Java server waits five seconds for more data to be sent but will time out as nothing more is ever sent.
The dartlang client should use the writeln function or appent a newline character to the end of its messages for the Java server BufferedReader to return.
When I try to send data on the lingering connection, it nevers arrives on the server nor is any error detected on the print writer. This applies to the heartbeat system too.
I have a semi-heartbeat system running. The point of it was to check the "out" error if it happens, but it never does. I have setKeepAlive on for both the app and the server, I am checking out.checkError(), nothing is detecting a lingering connection.
With or without keep alive the same thing happens.
Socket Creation (takes place in a thread):
Socket socket = new Socket(serverAddr, port);
socket.setKeepAlive(true);
Heart Beat System (also threaded):
public void heartbeat(){
new Thread(new Runnable() {
public void run() {
while(connected == true){
try{
Thread.sleep(120000);
}catch (Exception e){
}
handlerObject.sendMessage(String.valueOf((char) 1));
}
}
}).start();
}
Send Message is defined as:
public void sendMessage(String data){
try {
PrintWriter out = new PrintWriter(socket.getOutputStream());//, true);
out.println(data + "\r\n");
out.flush();
if(out.checkError()) {
socket.close();
}
}catch (Exception e){
try{
socket.close();
} catch (Exception z){
}
}
}
I might be firewall blocking the traffic on sever ,please check by turning off firewall on sever or adding appropriate rule (since you are facing no error so it might be that firewall blocking traffic)
The solution here was to use socket.setSoTimeout(milliseconds); and have the server send a heart beat a few seconds before that. If the client doesn't recieve a heartbeat before then it it will timeout. I can now catch that exception and reconnect.
How to restart ServerSocket after IOException?
My server socket sometimes gets an EOFException and then stops accepting new connections. To solve this I have tried closing the old server socket and creating a new one after the exception is thrown. However even after the new server socket is created, new connections are not accepted. Can some one see why this does not work?
public Server() throws IOException {
try {
listen(port);
}
catch (IOException e) {
System.out.println("Server() - IO exception");
System.out.println(e);
/*when an exception is caught I close the server socket and try opening it a new one */
serverSocket.close();
listen(port);
}
}
private void listen(int port) throws IOException {
serverIsListening = true;
serverSocket = new ServerSocket(port);
System.out.println("<Listening> Port: " + serverSocket);
while (serverIsListening) {
if (eofExceptionThrown){ //manually triggering an exception to troubleshoot
serverIsListening = false;
throw new EOFException();
}
//accept the next incoming connection
Socket socket = serverSocket.accept();
System.out.println("[New Conn] " + socket);
ObjectOutputStream oOut = new ObjectOutputStream(socket.getOutputStream());
// Save the streams
socketToOutputStreams.put(socket, oOut);
// Create a new thread for this connection, and put it in the hash table
socketToServerThread.put(socket, new ServerThread(this, socket));
}
}
2x entry point , one form catch: never ends well.
try {
listen(port);
}
catch (IOException e) {
System.out.println("Server() - IO exception");
System.out.println(e);
/*when an exception is caught I close the server socket and try opening it a new one */
serverSocket.close();
listen(port);
}
I would do in a loop, while a boolean is true:
while(needToListen){
try{
listen(port)
}catch(Exception ex){
if(exception is what needed to break the loop, like a message has a string on it){
break;
}
}
}
if(needToListen){
Log.e("something unexpected, unrecoverable....");
}
My server socket sometimes gets an EOFException and then stops accepting new connections
No it doesn't. ServerSockets never get EOFExceptions. Rather, one of your accepted Sockets is getting an EOFException, which is only to be expected, and you are closing both that Socket, which is correct, and the ServerSocket, which is incorrect. Exceptions on accepted sockets don't affect the listening socket.
In my Server application I'm trying to handle the Server which is using ServerSocket like,
Start the server and wait for connection.
Stop the server which is connected with a client.
Stop the server which is waiting for a client.
I can able to start the server and make it to wait for client inside a thread using
socket = serverSocket.accept();
What I want to do is I want manually close the socket which is waiting for connection, I have tried using,
if (thread != null) {
thread.stop();
thread = null;
}
if (socket != null) {
try {
socket.close();
socket = null;
}
catch (IOException e) {
e.printStackTrace();
}
}
After executing the above code even though the socket becomes null, when I try to connect from client to server, the connection gets established, so my question is how to interrupt the serversocket which listening for connection over here,
socket = serverSocket.accept();
I think a common way of handling this is make the accept() call time out in a loop.
So something like:
ServerSocket server = new ServerSocket();
server.setSoTimeout(1000); // 1 second, could change to whatever you like
while (running) { // running would be a member variable
try {
server.accept(); // handle the connection here
}
catch (SocketTimeoutException e) {
// You don't really need to handle this
}
}
Then, when you wanted to shut down your server, just have your code set 'running' to false and it will shut down.
I hope this makes sense!
Just close the ServerSocket, and catch the resulting SocketClosedException.
And get rid of the thread.stop(). For why, see the Javadoc.