I'm trying to create a socket listener to a device that requires an acknowledgement before it sends the next set of data to the server. I'm able to send the acknowledgement but by the time a new connection is created and as a result I lose data. I have pasted my code below.
public void run() {
try {
servSoc = new ServerSocket(this.port);
File file = new File("logs.txt");
// creates the file
Socket server = null;
//FileWriter writer = new FileWriter(file);
while (true) {
try {
System.out.println("Waiting for client on port "
+ servSoc.getLocalPort() + "...");
server = servSoc.accept();
System.out.println("Just connected to "
+ server.getRemoteSocketAddress());
InputStreamReader in = new InputStreamReader(server.getInputStream());
//InputStreamReader in = new InputStreamReader(server.getInputStream());
DataOutputStream out =
new DataOutputStream(server.getOutputStream());
new Thread(new LogWriter(in, out)).start();
// Writes the content to the file
if (servSoc.isClosed()) {
System.out.println("Connection closed....");
servSoc.close();
}
} catch (SocketTimeoutException s) {
System.out.println("Socket timed out!");
s.printStackTrace();
break;
} catch (IOException e) {
e.printStackTrace();
break;
}
}
} catch (IOException ex) {
java.util.logging.Logger.getLogger(SenselSocketListner.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
} finally {
}
}
public static void main(String args[]) {
int port = 8294;
Thread t = new SenselSocketListner(port);
t.start();
}
My log writer thread is given below.
public class LogWriter implements Runnable {
InputStreamReader in;
DataOutputStream out;
public LogWriter(InputStreamReader in, DataOutputStream out) {
this.in = in;
this.out = out;
}
#Override
public void run() {
try {
File file = new File("logs.txt");
// creates the file
if (!file.exists()) {
System.out.println("Creating File");
file.createNewFile();
}
String inputLine = null;
BufferedReader input = new BufferedReader(in);
System.out.println("Writing data....");
while ((inputLine = input.readLine()) != null) {
//System.out.println("Test");
System.out.println("Sending Acknowledgement....");
out.writeUTF("Upload successful");
out.writeUTF("Ok");
FileWriter fstream = new FileWriter(file, true);
BufferedWriter fbw = new BufferedWriter(fstream);
fbw.write(inputLine);
fbw.newLine();
fbw.flush();
fbw.close();
}
//DataOutputStream out =
//new DataOutputStream(server.getOutputStream());
//out.writeUTF("Thank you for connecting to " + server.getLocalSocketAddress() + "\nGoodbye!");
//server.close();
} catch (IOException ex) {
Logger.getLogger(LogWriter.class.getName()).log(Level.SEVERE, null, ex);
ex.printStackTrace();
}
}
}
Person concerned with the device suggested that I might not be sending the acknowledgement fast enough. Please help me to find a way to speed this up, I have notices a delay after the statement "System.out.println("Writing data....");" in the log writer.
Does the device really understand the result of writeUTF()? Unless it is implemented in Java it is highly unlikely. You should surely just be writing the bytes or chars of the message directly.
Other notes:
Creating a new log file per line is wasting time. Open the file before the read loop, and close it afterw the loop.
Closing the server socket if it's already closed doesn't make sense.
You should close the accepted socket when readLine() returns null, in the reading thread.
The while loop in run in LogWriter traps your app until the socket is closed. If you need to converse on a socket, you'll have to know what to expect - as defined by a protocol. If it is one line, just read one line. If it is a text file, you'll have to devise a protocol that informs you about the number of bytes to expect.
Also, logging should be done on a single open log file, without close after each line.
Related
I'm sending a file and its name through Socket to a ServerSocket.
It works "partially" -- the server gets the file and saves it to disk but
it does not exit the loop in the copy() method in the ClientSession class.
public class Client{
DataOutputStream dos =null;
DataInputStream dis=null;
File f =new File("c:/users/supernatural.mp4");
public static void main(String[]ar) throws Exception{
try {
System.out.println("File upload started");
Socket socc = new Socket("localhost",8117);
dos = new DataOutputStream(socc.getOutputStream());
//send file name
dos.writeUTF(f.getName());
//send the file
write(f,dos);
//Files.copy(f.toPath(),dos);
//this prints
System.out.println("Data has been sent...waiting for server to respond ");
dis = new DataInputStream(socc.getInputStream());
//this never reads; stuck here
String RESPONSE = dis.readUTF();
//this never prints prints
System.out.println("Server sent: "+RESPONSE);
} catch(Exception ex) {
ex.printStackTrace();
} finally {
//close the exceptions
clean();
}
}
private static void write(File f,DataOutputStream d) throws Exception{
int count;
DataInputStream din = new DataInputStream(new BufferedInputStream(new FileInputStream(f)));
byte array[] = new byte[1024*4];
while((count =din.read(array)) >0){
d.write(array,0,count);
}
d.flush();
//this prints
System.out.println(" done sending...");
din.close();
}
}
//Server
public class MySocket implements Runnable{
int worker_thread=2;
volatile boolean shouldRun =false;
ServerSocket server;
String port = "8117";
//ExecutorService services;
static ExecutorService services;
public MySocket() {
this.server = new ServerSocket(Integer.valueOf(port));
services = Executors.newFixedThreadPool(this.worker_thread);
}
//A METHOD TO RUN SERVER THREAD
#Override
public void run(){
while(this.shouldRun){
Socket client =null;
try{
client = server.accept();
}catch(Exception ex){
ex.printStackTrace();
}
//hand it over to be processed
this.services.execute(new ClientSessions(client));
}
}
public static void main(String[]ar) throws Exception{
Thread t = new Thread(new MySocket());
t.start();
}
}
//the ClientSession
public class ClientSessions implements Runnable{
Socket s;
public ClientSessions(Socket s){
this.s = s;
}
DataInputStream dis=null;
DataOutputStream dos=null;
boolean success =true;
#Override
public void run(){
//get the data
try{
//get inside channels
dis = new DataInputStream(this.s.getInputStream());
//get outside channels
dos = new DataOutputStream(this.s.getOutputStream());
//read the name
//this works
String name=dis.readUTF();
String PATH_TO_SAVE ="c://folder//"+name;
//now copy file to disk
File f = new File(PATH_TO_SAVE);
copy(f,dis);
//Files.copy(dis,f.toPath());
//this doesnt print, stuck in the copy(f,dis) method
System.out.println("I am done");
success =true;
}catch(Exception ex){
ex.printStackTrace();
}finally{
//clean resources...
clean();
}
}
//copy from the stream to the disk
private void copy(File f,DataInputStream d)throws Exception{
f.getParentFile().mkdirs();
f.createNewFile();
int count =-1;
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
byte array[] = new byte[1024*8];
count =d.read(array);
while(count >0){
out.write(array,0,count);
count =d.read(array);
System.out.println("byte out: "+count);
}
//this never prints
System.out.println("last read: "+count);
out.flush();
out.close();
if(success)dos.writeUTF("Succesful");
else dos.writeUTF("error");
}
}
//for the clean method i simply have
void clean(){
if(dis!=null)dis.close();
if(dos!=null)dos.close();
}
I commented this //Files.copy(dis,f.toPath()); from server
because it does not go to next line after writing file to disk, sometimes even stuck there.
Could some pls point me in the right path, I believe i am doing something very wrong here
dont know if this is helpful but the client runs in eclipse and server in netbeans
Think about your procotol:
The Client sends the file name, then sends the binary file, then waits for the server response.
The Server reads the file name, then the binary file until the stream is closed, then sends the success message.
But the stream is never closed since the client is waiting for the response, hence you have a deadlock in your protocol.
This is usually solved by sending the file size first and having the server read exactly that many bytes.
Alternatively you can use the TCP's one-way shutdown feature to send a signal to the server that the output stream of the socket is closed. That can be done with socc.shutdownOutput();
And please use try-with-resources to avoid resource leaks (you must close the Socket, too).
Fixed Client:
try {
System.out.println("File upload started");
try (Socket socc = new Socket("localhost", 8117);
DataOutputStream dos = new DataOutputStream(socc.getOutputStream());
DataInputStream dis = new DataInputStream(socc.getInputStream())) {
// send file name
dos.writeUTF(f.getName());
// send the file
Files.copy(f.toPath(), dos);
dos.flush();
System.out.println("Data has been sent...waiting for server to respond ");
// signal to server that sending is finished
socc.shutdownOutput();
String RESPONSE = dis.readUTF();
// this never prints prints
System.out.println("Server sent: " + RESPONSE);
}
} catch (Exception ex) {
ex.printStackTrace();
}
Server:
public class MySocket implements Runnable {
int worker_thread = 2;
volatile boolean shouldRun = true;
ServerSocket server;
int port = 8117;
ExecutorService services;
public MySocket() throws IOException {
this.server = new ServerSocket(port);
services = Executors.newFixedThreadPool(this.worker_thread);
}
// A METHOD TO RUN SERVER THREAD
#Override
public void run() {
while (this.shouldRun) {
Socket client = null;
try {
client = server.accept();
} catch (Exception ex) {
ex.printStackTrace();
}
// hand it over to be processed
this.services.execute(new ClientSessions(client));
}
}
public static void main(String[] ar) throws Exception {
new MySocket().run();
}
}
class ClientSessions implements Runnable {
Socket s;
public ClientSessions(Socket s) {
this.s = s;
}
#Override
public void run() {
// get the data
try (DataInputStream dis = new DataInputStream(this.s.getInputStream());
DataOutputStream dos = new DataOutputStream(this.s.getOutputStream())) {
// read the name
// this works
String name = dis.readUTF();
String PATH_TO_SAVE = name;
// now copy file to disk
File f = new File("c://folder", PATH_TO_SAVE);
Files.copy(dis, f.toPath());
dos.writeUTF("Succesful");
System.out.println("I am done");
} catch (Exception ex) {
ex.printStackTrace();
} finally {
try {
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The issue with your code is, that you read from an input stream of a socket, that is never closed.
DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(f)));
byte array[] = new byte[1024*8];
count =d.read(array);
while(count >0){
out.write(array,0,count);
count =d.read(array);
System.out.println("byte out: "+count);
}
//this never prints
System.out.println("last read: "+count);
d.read(array) is actively trying to read from the socket, blocking until it receives something. Since the InputStream is actively blocking, it never returns a value less than or equal to 0. This is because the stream awaits the next package from the other end of the Socket.
Closing the Socket after sending the File should help you. In that case, the end of the Stream is reached and the InputStream returns.
Note: The InputStream you are reading from will (if the socket is closed) return a -1, as you can see within the JavaDoc.
In your case, this however might not be viable!
You want to answer the Client with "okay", or "error". If you close the socket, you cannot answer through the same Socket. The solution to this can be complex.
This situation is a bit tricky. Most frameworks out there have a Thread that reads from the SocketInputStream and passes the return value to some sort of handler (in blocking IO). Your while loop basically is this main reading loop inside the Thread. This loop will only exit, if the connection is lost and therefor the System.out.println("last read: "+count); could be changed to System.out.println("disconnected");
To keep it simple: You could give an estimation on how big the file will be and (just for testing purposes) write something like this:
DataOutputStream out = new DataOutputStream(new
BufferedOutputStream(new FileOutputStream(f)));
byte array[] = new byte[/* Big enough */ 1024 * 1024 * 8];
d.read(array); // Read the file content
out.write(array); // Write to the file
//this never prints
System.out.println("last read: "+count);
I have left out every error check here! This means that you only read one package from the server, which has to be the File.
My application connects to hardware which is basically a plotter machine which prints data based on the command. I am doing socket connection and firing some commands. In the hardware I can see command has been reached but I am not able to get return value of executed command. Below is the sample code. There is no error but at the execution on this line String cmd = in.readLine(); it got stuck.
Main.Java
public class Test
{
public static void main(String[] args)
{
try
{
PrintTest printTest = new PrintTest();
printTest.print();
}
catch (Throwable e)
{
e.printStackTrace();
}
}
}
Method
public void print() throws IOException
{
Socket socket = null;
try
{
socket = new Socket();
socket.connect(new InetSocketAddress(host, port), 10);
System.out.println("isConnected :- " + socket.isConnected());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
out.write("TC1004,1;");
out.flush();
String cmd = in.readLine();
System.out.println("Recieved: " + cmd);
}
catch (Throwable ex)
{
ex.printStackTrace();
}
finally
{
if (socket != null)
{
socket.close();
}
}
}
}
readLine(); will read (or block) until it encounters a line feed, so that's why you're getting stuck. However you didn't use a line feed in the command you sent either, which is suspicious since there must be some agreed form in the protocol to be able to tell commands apart (flush() is not enough).
I suspect the plotter is still waiting for you to finish your command with a \nbefore you can read anything it returns.
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 trying to write a client-server system using Sockets in java, however I cannot seem to read data sent from the server to the client.
Here is the code for the client:
public class ClientSocket
{
Socket clientSocket = null;
PrintWriter out = null;
BufferedReader in = null;
// establish a connection to All Care's server application through socket 4444 (adjust localhost to reflect the IP address that the server
// is being run from)
public ClientSocket()
{
try
{
clientSocket = new Socket("localhost", 4445);
out = new PrintWriter(clientSocket.getOutputStream());
in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
}
catch (IOException e)
{
System.out.println("Could not connect to All Care Server Application");
}
}
public void closeClientSocket()
{
try
{
clientSocket.close();
}
catch (IOException e)
{
System.out.println("Could not close connection to All Care Server Application");
}
}
public String getMessageFromServer()
{
try
{
String input = in.readLine();
return input;
}
catch (IOException e)
{
System.out.println("Could not read message from server");
}
return "No Data";
}
public void sendMessageToServer(String message)
{
out.write(message);
}
}
And here is the Server code:
public class ArFileServer {
public static void main(String[] args)
{
ServerSocket serverSocket = null;
boolean listening = true;
try
{
serverSocket = new ServerSocket(4445);
// infinite loop to continually listen for connection requests made by clients
while (listening)
{
new ClientConnection(serverSocket.accept()).start();
if (serverSocket != null)
{
System.out.println("Connection to client established");
}
}
serverSocket.close();
}
catch (IOException e)
{
System.out.println("Error could not create socket connection to port");
}
}
}
public class ClientConnection extends Thread
{
private Socket socket = null;
public ClientConnection(Socket socket)
{
super("ClientConnection");
this.socket = socket;
}
// the thread that runs after a connection to the server has been accepted
#Override
public void run()
{
try
{
PrintWriter out = new PrintWriter(socket.getOutputStream());
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
sendMessagetoClient(out, "CONNECTION SUCCESS");
// check login credentials sent from client to the server
// if valid send back their encrypted password, otherwise output a login error message
// wait for user input and then do various processes based on their requests
in.close();
out.close();
socket.close();
}
catch (IOException e)
{
System.out.println("Client socket connection error");
}
}
// sends a message to the client
void sendMessagetoClient(PrintWriter out, String message)
{
out.write(message);
}
// listens for a message from the client
String getMessageFromClient(BufferedReader in)
{
try
{
String input = in.readLine();
return input;
}
catch (IOException e)
{
System.out.println("Could not read message from client");
}
return "No Data";
}
And here is the line of code im using to see if the data is being sent.
System.out.println(clientSocket.getMessageFromServer());
In your sendMessageToClient() method, you need to flush:
void sendMessagetoClient(PrintWriter out, String message)
{
out.write(message);
out.flush();
}
Or, when you create the PrintWriter, use the constructor with autoflush:
PrintWriter out = new PrintWriter(socket.getOutputStream(),true);
And when you write, instead of out.write(message) use printf() or println().
There are several problems here.
You are reading lines but you aren't writing lines.
You aren't checking the result of readLine() for null, which means the peer has closed the connection, which means you must do likewise.
You aren't flushing the PrintWriter after you write.
You are closing things in the wrong order. You must close the output writer/stream you have attached to the socket. Doing that flushes it and then closes the input stream/reader and the socket. Doing this in the wrong order loses the flush. Once you've closed the output you don't need the other two closes.
You are using PrintWriter, which swallows exceptions, across a network, where you need to know about exceptions and errors in communication, and you aren't checking for errors either. Use a BufferedWriter.
in the clint code you are not connecting with server socket.
for clint socket connection
socket soc= new socket ("server host ip",port);
In a class where I have ServerSocket listening for incoming connections, following is the code:
while(isRunning)
{
try
{
Socket s = mysocketserver.accept();
acknowledgeClient(s);
new ClientHandler(s).start(); //Start new thread to serve the client, and get back to accept new connections.
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
And following is acknowledgeClient(Socket s) code.
ObjectInputStream in = new ObjectInputStream(s.getInputStream);
ObjectOutputStream out = new ObjectOutputStream(s.getOutStream);
String msg = in.readObject().toString();
System.out.println(msg+" is Connected"); //Show who's connected
out.writeObject("success"); //Respond with success.
in.close();
out.close();
The run() method of the ClientHandler.
try
{
in = new ObjectInputStream(client.getInputStream());
out = new ObjectOutputstream(client.getOutputStream());
String msg = "";
while(!msg.equalsIgnoreCase("bye"))
{
msg = in.readObject().toString();
System.out.println("Client Says - "+msg);
out.writeObject("success");
}
in.close();
out.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
And following is the way how client program communicates with this Echo Server.
try
{
int count = 10;
client = new Socket("localhost",8666);
in = new ObjectInputStream(client.getInputStream());
out = new ObjectOutputstream(client.getOutputStream());
out.writeObject("Foo");
System.out.println("Connection Status : "+in.readObject().toString());
while(count>0)
{
out.writeObject("Hello!");
String resp = in.readObject().toString(); //Getting EOFException here.
System.out.println("Sent with :"+resp);
count--;
Thread.sleep(1000);
}
out.close();
in.close();
client.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
As you might have noticed that, after the client is acknowledged after connection, I close the read/write streams, and from new thread which is serving the client, I'm opening the stream again, and from the server reading/writing from the connected socket is started, but as soon as I attempt to read server's response on sending Hello! by client, it crashes with EOFException instead of getting success.
I know the causes for which EOF occurs but not getting the clue that why is it happening here, I'm not attempting to read socket that has nothing in its stream (it should have success as written by server).
Is it too early that client is attempting to read socket before server has printed Hello! on its end and written success as response?
P.S. : I know its not a good way to ask question by putting so much code, we're expected here to get answers of the issue and understand it rather than having our problem fixed by others and get away. So, I've provided this much code to show all aspects from the problem.
I studied the source code of ObjectInputStream, and it appears that the reference to the original input stream s.getInputStream() is stored inside the ObjectInputStream.
When you close the ObjectInputStream, s.getInputStream() is closed as well.
Once an input stream is closed, it cannot be opened again. Thus, you get an EOFException, which indicates that you are at the end of the stream (since the stream could not be opened again).
You should do something like this to acknowledge the client.
Inside the run() method of the ClientHandler:
try {
// acknowledge client
ObjectInputStream in = new ObjectInputStream(s.getInputStream());
ObjectOutputStream out = new ObjectOutputStream(s.getOutStream());
String msg = in.readObject().toString();
System.out.println(msg+" is Connected"); //Show who's connected
out.writeObject("success"); //Respond with success.
// end acknowledge client
String msg = "";
while(!msg.equalsIgnoreCase("bye"))
{
msg = in.readObject().toString();
System.out.println("Client Says - "+msg);
out.writeObject("success");
}
in.close();
out.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
If you want to isolate the acknowledge code in a seperate method, just be sure to maintain a proper reference to the same ObjectInputStream without closing the stream, then pass the reference around.
I'm opening the stream again, and from the server reading/writing from the connected socket is started,
Once a stream is close, you can't open it again. In fact you can't use two Object stream on the same stream this way at all.
Instead you should create an object stream for input and output once and only once and not close it until you have finished.
Well take a look at this program, i wrote it to understand multiple clients and server communication, your question is answered in this program.
The Client side code
public class ClientWala {
public static void main(String[] args) throws Exception{
Boolean b = true;
Socket s = new Socket("127.0.0.1", 4444);
System.out.println("connected: "+s.isConnected());
OutputStream output = s.getOutputStream();
PrintWriter pw = new PrintWriter(output,true);
// to write data to server
while(b){
if (!b){
System.exit(0);
}
else {
pw.write(new Scanner(System.in).nextLine());
}
}
// to read data from server
InputStream input = s.getInputStream();
InputStreamReader isr = new InputStreamReader(input);
BufferedReader br = new BufferedReader(isr);
String data = null;
while ((data = br.readLine())!=null){
// Print it using sysout, or do whatever you want with the incoming data from server
}
}
}
Server Side code
public class ServerTest {
ServerSocket s;
public void go() {
try {
s = new ServerSocket(44457);
while (true) {
Socket incoming = s.accept();
Thread t = new Thread(new MyCon(incoming));
t.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
class MyCon implements Runnable {
Socket incoming;
public MyCon(Socket incoming) {
this.incoming = incoming;
}
#Override
public void run() {
try {
PrintWriter pw = new PrintWriter(incoming.getOutputStream(),
true);
InputStreamReader isr = new InputStreamReader(
incoming.getInputStream());
BufferedReader br = new BufferedReader(isr);
String inp = null;
boolean isDone = true;
System.out.println("TYPE : BYE");
System.out.println();
while (isDone && ((inp = br.readLine()) != null)) {
System.out.println(inp);
if (inp.trim().equals("BYE")) {
System.out
.println("THANKS FOR CONNECTING...Bye for now");
isDone = false;
s.close();
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
try {
s.close();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new ServerTest().go();
}
}
Closing any input stream or output stream or reader or writer around a socket stream closes the socket, and by implication the other streams, readers, and writers.
Use the same streams, readers, writers for the life of the socket.