I'm having an issue trying to get a java server to realize an (android/java) client has closed a TCP socket connection. I figured when the client calls close() on the socket, the server would catch an IOException, but this is not the case. t_recv is a thread that receives from BufferedReader in, and t_send sends using a PrintWriter out. Closing in causes a timeout and crash, and closing out doesn't really seem to do anything. The PrintWriter is created in the contructor of the t_send thread, and BufferedReader is create in the contructor of the t_recv thread. Trying to debug this, I created blank run() methods in both threads, and the same behaviour occurs.
An interesting note: the client is an Android application, and whenever the emulator freezes and windows has to force close it, the IOException is caught in the server and the "User x.x.x.x left" message is displayed.
Client closing connection:
try {
// t_recv.in.close(); - times out and crashes
// t_send.out.close(); - appears to do nothing
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
Server waiting for client to disconnect:
for (;;)
{
try {
while ( (msg = in.readLine()) != null)
{
response = msg;
System.out.println(response);
server.broadcast(response);
}
} catch (IOException e) {
System.out.println("User '" + socket.getInetAddress().toString() + "' left");
try {
socket.close();
out.close();
in.close();
} catch (IOException e1) {
e1.printStackTrace();
System.exit(-1);
}
break;
}
}
Thanks for your time.
Assuming that in is a BufferedReader, the error is in this line:
while ( (msg = in.readLine()) == null);
That will loop for ever if in is currently at the EOF. It should be:
while ( (msg = in.readLine()) != null);
See javadoc for BufferedReader.readLine(), paying specific attention to the conditions in which it returns null.
Related
I have written a small Client/Server Program which already worked once but after adding Threads and some real input Data to it, i always get a closed Socket before being able to read the Object (the String). The Program always Prints "Client has already closed Connection!" from Function handleConnection in the ProcessDataThread.
ClientCode:
synchronized private static void sendToServer(){
Socket clientSocket = null;
BufferedOutputStream socketOut = null;
ObjectOutputStream out = null;
try{
String xmlToSend = "<startTag>\n<someOtherTag id=\"5555\">\n12345\n</someOtherTag>\n</startTag>\n";
Log.d(TAG, "Trying to send the following to the Server:" + xmlToSend);
//TODO load these from file
clientSocket = new Socket( "10.0.2.2", 7777);
socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
out = new ObjectOutputStream(socketOut);
out.writeObject(xmlToSend);
out.flush();
}catch(Exception ex){
Log.e(TAG, "Could not write File to Server.", ex);
}
finally{
try{
if(clientSocket != null){
clientSocket.close();
}
if(out != null){
out.close();
}
}catch(IOException ex){
Log.e(TAG, "Could not close Socket.");
}
}
}
ServerCode:
ReceiverThread:
public void run()
{
try {
ServerSocket server = new ServerSocket(port);
//Only block for 10 Seconds and try again
server.setSoTimeout(10000);
while(!server.isClosed() && !stopped){
//Run
Socket client = null;
try
{
client = server.accept();
System.out.println("Accepted ClientConnection from " + client.getRemoteSocketAddress());
new ProcessDataThread(client).start();
}
catch( SocketTimeoutException tx){
//nothing
}
catch ( IOException e ) {
e.printStackTrace();
}
finally {
if ( client != null )
try { client.close(); } catch ( IOException e ) { e.printStackTrace(); }
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
ProcessDataThread:
public class ProcessDataThread extends Thread {
Socket client;
public ProcessDataThread(Socket sock) {
// xmlToProcess = xmlString;
this.client = sock;
}
private String handleConnection() {
BufferedInputStream socketIn = null;
ObjectInputStream in = null;
String xmlToProcess = null;
try {
if(!client.isClosed()){
System.out.println("Trying to read from Stream;");
socketIn = new BufferedInputStream(client.getInputStream());
in = new ObjectInputStream(socketIn);
Object xmlString = in.readObject();
System.out.println("Read some Object from Stream:" + xmlString.toString());
if (xmlString instanceof String) {
xmlToProcess = (String) xmlString;
System.out.println("Received the following XML:\n" + xmlToProcess);
}
}else{
System.out.println("Client has already closed Connection!");
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (EOFException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (socketIn != null) {
socketIn.close();
}
if(client != null){
client.close();
}
} catch (IOException ioex) {
ioex.printStackTrace();
}
}
return xmlToProcess;
}
#Override
public void run() {
String xmlToProcess = handleConnection();
if (xmlToProcess == null || xmlToProcess.isEmpty()) {
// Es konnte kein String vom Client gelesen werden.
return;
}
System.out.println(xmlToProcess);
}
}
I made some changes with jboi's Suggestions. This is what i got now. The error stays the same. I don't even get to reading the Stream in the Server because client.getClosed()
is always true!
In the Client Code:
clientSocket = new Socket( "10.0.2.2", 7777);
clientSocket.setTcpNoDelay(true);
socketOut = new BufferedOutputStream(clientSocket.getOutputStream());
out = new ObjectOutputStream(socketOut);
out.writeObject(xmlToSend);
out.flush();
socketOut.flush();
//Close Output on Socket to signalize the Server that we finished writing!
clientSocket.shutdownOutput();
in = clientSocket.getInputStream();
byte[] receivedData = new byte[8192];
while(in.read(receivedData) != -1) {
//Wait for the Server to Close the Connection
}
In the Server Code
socketIn = new BufferedInputStream(client.getInputStream());
in = new ObjectInputStream(socketIn);
Object xmlString = in.readObject();
System.out.println("Read some Object from Stream:" + xmlString.toString());
if (xmlString instanceof String) {
xmlToProcess = (String) xmlString;
System.out.println("Received the following XML:\n" + xmlToProcess);
}
out = client.getOutputStream();
out.write(1);
//Signalize the Client that we have read everything
client.shutdownOutput();
It is very probable that your client has closed the socket in the finally block before the server was able to read the data.
In your clients finally block you should use socket.shutdownOutput, then read on the client all incoming data till EOF and then close the socket.
On your server you read till EOF and then send an object as kind of acknowledge, e.g. Number of bytes in the message. You also end the send with socket.shutdownOutput() as you've done at the client. This puts again an EOF at the end of the data. This EOF is received by the client and it will finally close the socket.
The issue seems to be the client and server are unable to identify each others state:
Client sending data to server, where server has closed the connection
Server sending/reading data to client , where client has closed the connection
Either are unable to coordinate with each other, solutions could be to establish a proper state machine. Some examples in Google if you search for (client and server state machine) gives mathematically definite state machine examples for your application: hope this comment helps.
Hence it's not useful to look into this problem in solution perspective and probably start using protocols in place like : telnet etc .
Ok now i'm feeling stupid.
I closed the Socket inside the Server Code myself.
After accepting a connection the following is executed inside the finally Block:
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
The reason that there is this finally Block was because i didn't use Threads before so the ReceiverThread also did handle the Connection and therefore close the socket after using it.
I then moved the code to the new Thread and forgot to remove that finally block!
You can't use a buffered input stream and another kind of stream on the same socket. The buffered stream will steal data from the other one. Make up your mind. The ObjectInputStream will do everything you need. Just use that.
EDIT Re your edit, 'socket closed' means that you closed your socket and then continued to use it.
I am facing a problem regarding sockets on the server side. My code is client side. Whenever I am sending a second message (whether it's a heartbeat or any other message) it will fail on the server, and the server side logs an 'error in message format' but the same message will succeed the first time.
Please help me out with this.
my client code :
public class Main {
String Host = "";
int port = 1111;
Socket ss;
BufferedReader in;
BufferedWriter out;
String recv;
public void connection() {
try {
ss = new Socket(Host, port);
ss.setSoTimeout(30000);
in = new BufferedReader(new InputStreamReader(ss.getInputStream()));
out = new BufferedWriter(new OutputStreamWriter(ss.getOutputStream()));
} catch (UnknownHostException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
}
}
public void sender(String regTag) {
if (ss == null || !ss.isConnected()) {
connection();
}
try {
if (out != null && regTag != null) {
out.write(regTag + "\n");
System.out.println("message::" + regTag);
out.flush();
}
} catch (Exception e) {
e.printStackTrace();
}
}
public String Reciver() {
try {
recv = in.readLine();
if (ss != null && recv != null) {
return recv;
} else {
disconnect();
String Str = "nothing...Sorry";
return Str;
}
} catch (Exception e) {
e.printStackTrace();
return "Exception";
}
}
public void disconnect() {
try {
System.out.println("socket discoonected.");
ss.close();
in.close();
out.close();
connection();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Main me = new Main();
me.connection();
String hbhb = "`SC`0004HBHBB7BDB7BD";
String login = "`SC`00581.000000CRBTSRVM 00000001DLGLGN 00000002 TXBEG LOGIN:USER=cvbs,PSWD=password DEB2CCA8";
String cut = "`SC`00631.000000CRBT00PPSPHS00000002DLGCON 00000003 TXBEG CUT PPS FEE:MDN=9610023,CUTFEE=1000,REASON=1 BDB7DA88";
me.sender(hbhb.trim());
String str = me.Reciver();
System.out.println("Response :::" + str);
me.sender(login.trim());
String str1 = me.Reciver();
System.out.println("Response hb:::" + str1);
}
It receives null ... all the time on every second message
logs from serverside
[121_SERVER] 2012-05-03 14:26:37:213 [ERROR] [ServerAccptor.java:254] ->
errorCode = [UIP-80015] errorDesc = [Uip server has a exception when receiving data from the client,will remove the client,Server [adapter id=121],.]
at com.ztesoft.zsmart.bss.uip.adapter.socket.server.ServerAccptor.listenMsg(ServerAccptor.java:252)
at com.ztesoft.zsmart.bss.uip.adapter.socket.server.ServerAccptor.run(ServerAccptor.java:117)
Caused by: errorCode = [UIP-9102] errorDesc = [] Describing= [read client message error,will remove client.]
at com.ztesoft.zsmart.bss.uip.adapters.socket.server.mml.MMLServerAdapter.readByteField(MMLServerAdapter.java:784)
at com.ztesoft.zsmart.bss.uip.adapters.socket.server.mml.MMLServerAdapter.reciveWholeMsg(MMLServerAdapter.java:671)
Your code embodies numerous bad practices and fallacies.
You are logging exceptions and otherwise ignoring them, and doing strange things like letting the program continue, returning "Exception", etc. This is poor programming. Exceptions are there to help you, not to have bandaids applied them to hide the blood. The code will not self-heal under the bandaid. For example you should just declare connection() to throw IOException and let the callers deal with it.
As a consequence of (1) you have numerous ss != null tests. You shouldn't even be in a state where you need to do I/O and ss could be null. Again correct exception handling and propagation would avoid this.
As a further result of (1), you have numerous !ss.isConnected() tests, apparently in the mistaken belief that this API will tell you if the connection has been dropped. It won't. It will only tell you whether you have connected the Socket yet. In your code, as you are calling ss = new Socket(...), you have connected it, or else you haven't executed that code yet. Calling isConnected() adds no value.
You are closing the socket input stream before the output stream. This is incorrect. You should close only the output stream, and the socket itself in a finally block. That way the output stream gets flushed. Closing the input stream closes the socket and the output stream without flushing it. Don't do that.
Actually the correct answer is that there is no \n in the MML response. So this never works:
recv = in.readLine();
You have to read the message length given in the message header part of the response and read up to that length.
UPDATE:
there are syntax errors in your MML commands. It seems that you are using version 1.00 of the protocol, so this is a sample that works (look for differences):
`SC`00741.00CRBT PPS 00000001DLGCON 00000004TXBEG PPS CUT FEE:mdn=93784050910,fee=300,id=20140812165011003 F3E0ADDF
You must fill the extra spaces with 0 just in numbers, elsewhere you have to fill them with blank spaces.
I'm having problems with a simple java socket client: the connection is established properly and both server and client receive and send data. When the client loses connectivity for a couple of seconds, the socket is finished and reestablished. This is done ok but in that moment, the last received message by the client (previous to the reconnection) is received again (2 receptions of the same message) with no reason.
My code is:
To start the socket:
Socket sock = new Socket();
sock.bind(null);
InetSocketAddress isa = new InetSocketAddress(serverIPAddress,serverPort);
sock.connect(isa, conectionTimeOut);
sock.setKeepAlive(true);
InputStreamReader isR = new InputStreamReader(sock.getInputStream(), "UTF8");
reader = new BufferedReader(isR);
out = new BufferedWriter(new OutputStreamWriter(
sock.getOutputStream(), "UTF8"));
Reading data:
public class IncomingReader implements Runnable {
String message = "";
#Override
public void run() {
Thread thisThread = Thread.currentThread();
while (readerThread == thisThread) {
try {
while ((message = reader.readLine()) != null) {
manageServerMessage(message);
}
} catch (IOException e) {
Log.d(General.TAG, e.getMessage()+" "+e.getCause());
}
}
When the connection is lost:
public void stopSocket() {
readerThread = null;
try{
if (reader != null){
reader.close();
reader=null;
}
} catch (IOException e) {
Log.d(General.TAG, e.getMessage()+" "+e.getCause());
}
try{
if (out != null)
out.close();
} catch (IOException e) {
Log.d(General.TAG, e.getMessage()+" "+e.getCause());
}
try{
if (sock != null){
sock.close();
sock=null;
}
} catch (IOException e) {
Log.d(General.TAG, e.getMessage()+" "+e.getCause());
sock=null;
}
readerThread = null;
}
How are you re-establishing your Socket connection? I can see 2 possibilities at this stage...
You aren't fully removing all 'old' references before you recreate the connection. Are you creating a brand new Socket? BufferedReader? IncomingReader thread? etc. If there is something that you haven't recreated, it might be holding on to the previous value. If you're reusing your IncomingReader rather than creating a new one, it might still hold an old value.
If the connection is closed, how are you handling it on the Server side? If your Server is trying to send information to the Client, but the connection is broken, the Server may try to re-send the last message once the connection is re-established. Another possibility, if your Server doesn't close() the connection when it is broken, it too might be holding on to some old data.
Basically, as best as you can, you need to make sure that when the connection breaks, everything related to the connection on both the Client and the Server is completely closed and recreated using new Objects. If everything is a new Object, there's no possibility of any old data hanging around to confuse things.
I have three classes, the client, the server and the handler (which is going to handle the server connections) as I show below:
// The Client
public void sendSomePackage() {
try {
socket = new Socket("localhost", 54321);
sos = socket.getOutputStream();
oos = new ObjectOutputStream(sockOutput);
} catch (IOException e) {
e.printStackTrace(System.err);
return;
}
// About to start reading/writing to/from socket
try {
Package package = new Package(100);
oos.writeObject(pacote);
} catch (IOException e) {
e.printStackTrace(System.err);
}
try {
Thread.sleep(50);
} catch (Exception e) {
e.printStackTrace();
}
// Done reading/writing to/from socket, closing socket.
try {
sock.close();
} catch (IOException e) {
System.err.println("Exception closing socket.");
e.printStackTrace(System.err);
}
//Exiting
}
Now the server class:
// The Server - with a method that just wait for connections
public void waitForConnections() {
while (true) {
try {
socket = serverSocket.accept();
// Server:Accepted new socket, creating new handler for it
SimpleHandler handler = new SimpleHandler(socket);
handler.start();
// Server:Finished with socket, waiting for next connection
}
catch (IOException e){
e.printStackTrace(System.err);
}
}
}
My handler, which just handle the server connections:
#Override
public void run() {
//Handler: Handler run() starting
while (true) {
try {
package = (Package) ois.readObject();
if (pacote != null) {
System.out.println("Package received " + pacote.getSourceid());
}
} catch (Exception e) {
e.printStackTrace(System.err);
break;
}
}
try {
// SimpleHandler:Closing socket
sock.close();
ois.close();
} catch (Exception e) {
// Handler: Exception while closing socket, e=" + e);
e.printStackTrace(System.err);
}
}
The idea is the client send some 'package' object to my server which is going to keep running receiving the 'package' object any time.
The connection works fine, but in the end of the program an exception is launched, this is the one:
Package received 100
java.io.EOFException
at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at br.ufscar.socket.SimpleHandler.run(SimpleHandler.java:45)
at java.lang.Thread.run(Unknown Source)
I already search for something on Google but nothing so far.
Any idea ?
This is working exactly as you want it to (probably). It reads the 100 then goes through the loop again (while(true) never stops looping until a break statement) and throws an exception because no more data has been sent and it goes to the catch statement and prints the error before exiting your while loop.
EOFException ist an IOException that indicates the end of an stream.
Here we say that if there aren't any more bytes to read then we should break out of the while loop before trying to read the object, etc.
while (true) {
if (ois.read() == -1) break;
//...rest of the code
}
Ok, this is how object streams work and the solution that works everywhere.
Object stream data is preceded by a 4 byte 'magical' sequence AC ED 00 05. An ObjectInputStream will peek for this data at construction time rather than before the first read. And that's logical: one wants to be sure it is a proper stream before being too far in an application. The sequence is buffered by the ObjectOutputStream at construction time so that it is pushed on the stream at the first write.
This method gives rise to complexities in buffered situations or transferring via sockets.
Fortunately there is a just as simple as effective solution to all these problems:
Flush the ObjectOutputStream immediately after construction!
ObjectOutputStream myStream = new ObjectOutputStream ( anotherStream );
myStream.flush();
If I kill the Socket Server process, my Socket client process does not receive any errors, it continues to loop forever on the following code:
public void run() {
while(readData) {
String inputLine = null;
try {
while((inputLine = m_inputStream.readLine()) != null) {
//do stuff
}
} catch (IOException e) {
readData = false;
}
}
}
How can I detect that the socket server is gone and terminate the loop?
Terminate the outer loop when the call to readLine() returns null.
No exception is thrown when the server closes the connection normally. The stream should return null to signal the end of data.
This can be done with a loop like this:
public void run() {
try {
while (true) {
String line = input.readLine();
if (line == null)
break;
/* Process line. */
...
}
} catch (IOException ex) {
/* Handle the exception as desired. */
ex.printStackTrace();
}
}
Whilst the answer from erickson is correct, have you tried setting the socket read time-out properties? (e.g. sun.net.client.defaultReadTimeout). If it is possible that the server may take a long time responding, then this might be less useful as a solution to your problem but is a good idea nevertheless in many scenarios.