I'm trying to create a live messenger application. But the code hangs when trying to readObject from an ObjectInputStream with no reason. No exception is thrown.
try {
System.out.println("Trying to connect to server");
socket = new Socket(InetAddress.getByName("localhost"),6789);
System.out.println("Connected to server");
inputStream = new ObjectInputStream(socket.getInputStream());
outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.flush();
System.out.println("Streams are set up.");
window.toggleTyping(true);
System.out.println("Typing is now enabled");
String inputMsg = null;
do {
try {
System.out.println("Reading object");
inputMsg = (String)inputStream.readObject();
System.out.println("Object read");
} catch(ClassNotFoundException ee) {
System.out.println("Clas not found exception");
ee.printStackTrace();
}
} while(!inputMsg.equalsIgnoreCase("/exit"));
closeConnection();
}catch(IOException ex) {
ex.printStackTrace();
}
The last message that is printed is "Reading object".
try {
serverSocket = new ServerSocket(6789);
System.out.println("Socket created. About to accept connections");
Socket s = serverSocket.accept();
new Thread(new Chat(s)).start();
} catch(IOException e) {
e.printStackTrace();
}
And the class Chat:
public class Chat implements Runnable {
private Socket socket;
private ObjectOutputStream outputStream;
private ObjectInputStream inputStream;
public Chat(Socket s) {
System.out.println("Chat class constructor called");
this.socket = s;
try {
outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.flush();
inputStream = new ObjectInputStream(socket.getInputStream());
System.out.println("Chat streams are now set up");
}catch(IOException ex) {
ex.printStackTrace();
}
}
private void closeChat() {
try {
outputStream.close();
inputStream.close();
socket.close();
System.out.println("Chat is now closed");
}catch(IOException ex) {
ex.printStackTrace();
}
}
#Override
public void run() {
System.out.println("Chat class method run called");
try {
outputStream.writeObject("Connection is cool");
outputStream.flush();
System.out.println("Text sent");
String inputMsg = "";
do {
try {
inputMsg = (String)inputStream.readObject();
System.out.println("Message read:"+inputMsg);
}catch(ClassNotFoundException e) {
e.printStackTrace();
}
}
while(!inputMsg.equalsIgnoreCase("/exit"));
closeChat();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
The reason every chat is a different thread is that I'm planning to implement multiple one on one chats someday.
This is because the reading method is a blocking method. This means it is trying to read until it gets a -1 to show that the read data are finished. Ensure that the OutputStream which writes to this socket is sending this. So you invoke at sending socket the ObjectOutputStream.flush(); method after you wrote the data or just close the output stream after writing. Closing this one would'nt be reasonable, because probably you may want to send further data throug this stream later.
Just a general thing: You don't need to flush the outputstream immediatley after you have created it
Related
In a simple Server Client communication I always get the "java.net.SocketException: Connection reset" on the serverside, if the client does not close the outputstream of it's socket directly after sending out the data via BufferedWriter.
If I close the client's outputstream everything works fine.
But obviously the client wants eventually to send more than one String (then the server needs to handle the connection in a new Thread). But I don't even get that far, because ofe the problem above...
Thanks for helping!!
Here is some condensed code to show the problem.
This is the server class:
public class TestServerCharacterStream {
public static void main(String[] args) {
System.out.println("### Started");
TestServerCharacterStream testServerCharacterStream = new TestServerCharacterStream(9498);
testServerCharacterStream.waitForData();
System.out.println("### Terminated");
}
private int port;
private ServerSocket serverSocket;
private BufferedReader in;
public TestServerCharacterStream(int port) {
this.port = port;
try {
this.serverSocket = new ServerSocket(port);
System.out.println("[SERVER] : Server started!");
} catch (IOException e) {
System.err.println("Cannot open new server socket!");
e.printStackTrace();
}
}
public void waitForData() {
Socket clientSocket = null;
try {
System.out.println("[SERVER] : Wait for data on port " + port + " ...");
clientSocket = serverSocket.accept();
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String incoming = in.readLine();
System.out.println("[SERVER] : Incoming message: " + incoming);
} catch (IOException e) {
System.err.println("Error while accepting connection or reading input!");
closeStreamAndSocket(clientSocket, in);
closeServerSocket();
e.printStackTrace();
}
}
private void closeStreamAndSocket(Socket socket, BufferedReader in) {
try {
if (in != null) {
in.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
System.err.println("Cannot close stream or socket.");
e.printStackTrace();
}
}
private void closeServerSocket() {
try {
if (serverSocket != null) {
serverSocket.close();
}
} catch (IOException e) {
System.err.println("Cannot close serverSocket.");
e.printStackTrace();
}
}
}
This is the Client Class:
As mentioned, it works if closing the outputstream (see the comment). To use flush() or not does not make any difference. The only way to solve it is out.close();
But I want to use the BufferedWriter again, withot connect always again to the server.
public class TestClientCharacterStream {
public static void main(String[] args) {
System.out.println("### Started");
TestClientCharacterStream testClientCharacterStream = new TestClientCharacterStream("localhost", 9498);
testClientCharacterStream.sendData("Hello!!!");
System.out.println("### Terminated");
}
private InetSocketAddress adress;
private Socket clientSocket;
private BufferedWriter out;
public TestClientCharacterStream(String serverIp, int port) {
this.adress = new InetSocketAddress(serverIp, port);
try {
clientSocket = new Socket();
clientSocket.connect(adress, 10000);
this.out = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
} catch (IOException e) {
System.err.println("Something went wrong on instantiating a new TestClientCharacterStream");
e.printStackTrace();
}
}
public void sendData(String string) {
try {
out.write(string);
System.out.println("[CLIENT] : Sent new message: " + string);
out.flush();
out.close(); // If I don't close the stream, I'm going to get a "java.net.SocketException: Connection reset" on the server
} catch (IOException e) {
closeStreamAndSocket(clientSocket, out);
e.printStackTrace();
}
}
private void closeStreamAndSocket(Socket socket, BufferedWriter out) {
try {
if (out != null) {
out.close();
}
if (socket != null) {
socket.close();
}
} catch (IOException e) {
System.err.println("Cannot close stream or socket.");
e.printStackTrace();
}
}
}
The servers Output:
### Started
[SERVER] : Server started!
[SERVER] : Wait for data on port 9498 ...
Error while accepting connection or reading input!
java.net.SocketException: Connection reset
at java.base/sun.nio.ch.NioSocketImpl.implRead(NioSocketImpl.java:323)
at java.base/sun.nio.ch.NioSocketImpl.read(NioSocketImpl.java:350)
at java.base/sun.nio.ch.NioSocketImpl$1.read(NioSocketImpl.java:803)
at java.base/java.net.Socket$SocketInputStream.read(Socket.java:966)
at java.base/sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:270)
at java.base/sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:313)
at java.base/sun.nio.cs.StreamDecoder.read(StreamDecoder.java:188)
at java.base/java.io.InputStreamReader.read(InputStreamReader.java:177)
at java.base/java.io.BufferedReader.fill(BufferedReader.java:162)
at java.base/java.io.BufferedReader.readLine(BufferedReader.java:329)
at java.base/java.io.BufferedReader.readLine(BufferedReader.java:396)
at TestServerCharacterStream.waitForData(TestServerCharacterStream.java:40)
at TestServerCharacterStream.main(TestServerCharacterStream.java:12)
### Terminated
I'm trying to make a connection between a server and multiple clients, but it doesn't work even for one. All I want to do is to send from the client an object using the ObjectOutputStream class. The connection is made successfully at the beginning but when I try to send the object to the server it fails.
This is the client part which is written in the main method of a class:
Socket socket;
OutputStream out;
ObjectOutputStream fout;
boolean connected=false;
if (!connected) {
try {
socket = new Socket("localhost", 8000);
out = socket.getOutputStream();
fout = new ObjectOutputStream(out);
fout.flush();
connected = true;
fout.writeObject(ac1);//ac is an object of Plane class
} catch (Exception ex) {
System.out.println(ex.toString());
}
}
This is the server:
public class server {
static class ServerThread implements Runnable {
Socket client = null;
public ServerThread(Socket c) {
this.client = c;
}
public void run() {
try {
System.out.println("Connected to client : "+client.getInetAddress().getHostName());
Plane ac=null;
InputStream in=client.getInputStream();
ObjectInputStream fin=new ObjectInputStream(in);
while(client.isConnected()){
ac = (Plane)fin.readObject();
System.out.println(ac.toString());
}
client.close();
} catch (Exception e) {
// System.err.println(e.getMessage());
e.printStackTrace();
}
}
}
public static void main(String args[]) {
try {
ServerSocket server = new ServerSocket(8000);
while (true) {
Socket p = server.accept();
new Thread(new ServerThread(p)).start();
}
} catch (Exception ex) {
System.err.println("Error : " + ex.getMessage());
}
}
}
Could anyone tell me what is the problem?
Your client never closes the socket, and presumably exits, so the connection is reset. So close the socket.
NB isConnected() is not a valid loop condition. It will never become false. Your loop should terminate when EOFExceprion is caught.
I'm from Poland, so I'm sorry for any mistakes.
I've coding for a while a small server and client connection, when I stopped on annoying problem. When I send from client to server information (String), server can get it, but can't respone to it.
Here it is code.
Client
private static Socket socket;
public static void main(String args[]){
try{
String host = "localhost";
int port = 25002;
InetAddress address = InetAddress.getByName(host);
socket = new Socket();
socket.connect(new InetSocketAddress(host, port), 5000);
//Send the message to the server
System.out.println("< "+sendMessage(socket));
//socket.shutdownOutput();
System.out.println("> "+getMessage(socket));
}catch (SocketTimeoutException e){
System.out.println(e.getMessage()); // changed
}catch (IOException e){
System.out.println(e.getMessage()); // changed
}catch (IllegalBlockingModeException e){
System.out.println(e.getMessage()); // changed
}catch(IllegalArgumentException e){
System.out.println(e.getMessage()); // changed
}finally{
//Closing the socket
try{
socket.close();
}catch(Exception e){
System.out.println(e.getMessage()); // changed
}
}
}
public static String sendMessage(Socket client){
try {
String message = "test";
PrintWriter writer = new PrintWriter(client.getOutputStream(), true);
writer = new PrintWriter(client.getOutputStream(), true);
writer.print(message);
writer.flush();
writer.close();
return message;
} catch (IOException e) {
System.out.println(e.getMessage()); // changed
return "false";
}
}
public static String getMessage(Socket client){
try {
BufferedReader socketReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
return socketReader.readLine();
} catch (IOException e){
System.out.println(e.getMessage()); // changed
return "false";
}
}
And.. server
public class kRcon{
private static Socket socket;
private static ServerSocket serverSocket;
private static Thread u;
private static class Server extends Thread {
public void run() {
int port = 25002;
try {
serverSocket = new ServerSocket(port);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
while(true) {
try {
socket = serverSocket.accept();
BufferedReader socketReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter socketWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
String str = socketReader.readLine();
socketReader.close();
System.out.println(str);
socketWriter.write("test");
socketWriter.flush();
socketWriter.close();
}
}catch (IOException e1) {
e1.printStackTrace();
}
}
public static void init(){
try {
u = new Server();
u.setName("Server");
u.start();
} catch (IOException e) {
System.out.println(e.getMessage()); // changed
}
}
}
Results
If, I start server first all looks nice.
So, I start the client with parametr "test", nad output to console is:
< test
Socket is closed // changed
On server-side in console I have:
"test"
Socket is closed // changed
I tried to shutdown inputs and outputs and dosen't work.. I don't know to do now. Please help :c
Edited 2015-04-03
I've changed lines with comment "changed".
For Google, and readers
To fix problem, don't close StreamReaders nad StreamWriters on client's sides.
Thanks to EJP, for help!
Greetings from Poland.
When you get an exception, print it. Don't just throw away all that information. And don't return magic Strings either. In this case you should have let the exception propagate. If you had done all that you would have seen the exception SocketException: socket closed being thrown by getMessage(), and you would have had something concrete to investigate, instead of a complete mystery.
It is caused by closing the PrintWriter in sendMessage(). Closing either the input or output stream of a socket closes the other stream and the socket.
I got to stage where client and server communicate, sending messages from and to each other.
The problem I am having is how to close the connection without causing an error?
If I terminate one of the apps (either server or client) that causes the connection to be lost, and then it causes the loop that is waiting for input to loop indefinitely and showing null's.
I tried closing sockets, buffers and even the thread, didn't work.
This is the client side
public void onClick(View view) {
try {
EditText et = (EditText) findViewById(R.id.EditText01);
String str = et.getText().toString();
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
out.println(str);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
class ClientThread implements Runnable {
#Override
public void run() {
try {
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
socket = new Socket(serverAddr, SERVERPORT);
CommunicationThread commThread = new CommunicationThread(socket);
new Thread(commThread).start();
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
This is the server side
class ServerThread implements Runnable {
public void run() {
Socket socket = null;
try {
serverSocket = new ServerSocket(SERVERPORT);
} catch (IOException e) {
e.printStackTrace();
}
while (!Thread.currentThread().isInterrupted()) {
try {
socket = serverSocket.accept();
CommunicationThread commThread = new CommunicationThread(
socket);
new Thread(commThread).start();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
Both use these classes:
class CommunicationThread implements Runnable {
private Socket clientSocket;
private BufferedReader input;
public CommunicationThread(Socket clientSocket) {
this.clientSocket = clientSocket;
try {
this.input = new BufferedReader(new InputStreamReader(
this.clientSocket.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
public void run() {
while (!Thread.currentThread().isInterrupted()) {
try {
String read = input.readLine();
updateConversationHandler.post(new updateUIThread(read));
//***HERE EXTRA BIT FOR THE SERVER
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class updateUIThread implements Runnable {
private String msg;
public updateUIThread(String str) {
this.msg = str;
}
#Override
public void run() {
text.setText(msg);
}
}
the only difference is the server has this bit where it says above ***HERE EXTRA BIT FOR THE SERVER
PrintWriter out = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())), true);
out.println("Message recieved");
so basically, client connects, server accepts, then client sends message, servers receives message and shows it, and then sends "Message received" to the client, and the client shows it.
All this works fine, but once the connection is lost, they hang on showing null repeatedly, and I have to force the app to close.
You aren't checking for end of stream. If readLine() returns null, the peer has closed the connection, and you must do likewise and stop reading.
It's hard to believe you really need a new thread for every line to update the UI.
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.