I have server
ServerSocket socketListener = new ServerSocket(Config.PORT);
...
client = socketListener.accept();
and client
sock = new Socket("127.0.0.1", Config.PORT);
I want to transfer between them some serialized data using ObjectInputStream and ObjectOutputStream.
When I try to do
ObjectInputStream inputStream = new ObjectInputStream(socket.getInputStream());
Nothing happens neither on the server side nor client side. Everything falls on that line. Both the client and the server is trying to get the input stream from the socket, but it does not work nor the client nor the server.
How do I solve this problem so that I can pass the serialized data between client and server?
As the javadoc says:
Creates an ObjectInputStream that reads from the specified InputStream. A serialization stream header is read from the stream and verified. This constructor will block until the corresponding ObjectOutputStream has written and flushed the header.
So, since both the server and the client start by opening an InputStream, you implemented a deadlock: they both block until the other party has sent the stream header. If you start by opening an ObjectInputStream at client side, you must start by opening an ObjectOutputStream (and flushing immediately if necessary) at server-side (or vice-versa).
Related
Hello stack overflow world, I've been struggling with the most straight forward and common problem within Java IO, for some time, and now need your help to tackle it.
Check out this piece of code I have in a try block, within a thread.run():
// connect to client socket, and setup own server socket
clientSocket = new Socket(serverHostname, CLIENT_PORT);
//send a test command to download a file
String downloadFileName = "sample.txt";
DataOutputStream dataOutputStream = new DataOutputStream(clientSocket.getOutputStream());
System.out.println("Sending a request to download file : " + downloadFileName + " from user: Arsa node"); //todo: replace with node user later
dataOutputStream.writeUTF("D/sample.txt");
//close socket if host isn't detected anymore, and if socket doesn't become null suddenly
dataOutputStream.flush();
dataOutputStream.close();
System.out.println("****File has been sent****");
in = new DataInputStream(clientSocket.getInputStream());
byte[] retrievedFileData = new byte[8036];
if (in.readInt() > 0) {
System.out.println("Starting file download!");
in.read(retrievedFileData);
System.out.println("File data has been read, converting to file now");
//closing input stream will close socket also
in.close();
}
clientSocket.close();
2 Main questions that have been confusing me to death:
Why does dataOutputStream.close() need to be run for writeUTF to actually send my string to the server socket, I find that when I don't have dos.close(), data isn't retrieved on the other side, further because I close it, I no longer can read from the socket - as it seems the socket connection becomes closed when the Output Stream is previously closed...
What's a better way, following some sort of pattern to do this? For context, all I'm trying to do is write the filename I'm looking to download to my client, then read the response right away, which I expect to be bytes with the file, any error handling I will consider as a part of my development.
Overall, it shouldn't be complicated to write something to a socket, then read and ingest it's response...which doesn't seem to be the case here,
any help would be greatly appreciated! If the ServerSocket code snippet is needed I'm happy to share.
The observed behavior is just a side-effect of close(), as it calls flush() before closing to make sure any buffered data is sent. To solve your problem, you need to call the flush() method instead of closing.
This behavior is not unique to DataOutputStream: a lot of other OutputStream (or Writer) implementations apply buffering, and you will need to flush when you want to ensure the data is sent to the client, written to disk or otherwise processed.
BTW: The DataOutputStream and DataInputStream is for a very specific type of data serialization protocol that is particular to Java. You may want to consider carefully if this is the right protocol to use.
When I send only one object through a socket i am ok. But when i am trying to send two objects, i get
Exception in thread "main" java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source))
I have tried almost everything like flush() or reset() but none of them work.
public String SendObject(Object o) throws IOException {
OutputStream outToServer = client.getOutputStream();
ObjectOutputStream out = new ObjectOutputStream(outToServer);
out.writeUnshared(o);
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
return in.readUTF();
}
You're using an ObjectOutputStream to write the Object(s) from the client. You should be using an ObjectInputStream (not a DataInputStream) to read them on the server. To read two Objects might look something like,
InputStream inFromServer = client.getInputStream();
ObjectInputStream in = new ObjectInputStream(inFromServer);
Object obj1 = in.readObject();
Object obj2 = in.readObject();
Also, on the client, I think you wanted writeObject (instead of writeUnshared) like
ObjectOutputStream out = new ObjectOutputStream(outToServer);
out.writeObject(o);
While the other answers (e.g. #EJP's) are correct about the right way to send / receive objects and handle the streams, I think that the immediate problem is on the server side:
Exception in thread "main" java.net.SocketException: Connection reset
This seems to be saying that the connection has broken before the client receives a response. When the client side attempts to read, it sees the broken (reset) connection and throws the exception.
If (as you say) the sendObject method works first time, then I suspect that the server side is closing its output stream to "flush" the response ... or something like that.
You must use the same streams for the life of the socket, not new ones per send (or receive).
You need to decide between Object streams and Data streams. Don't mix them.
Don't try to mix between writeObject()/writeUnshared() and readUTF().
I'm writing a Java client/server application. It should allow clients to send text data to the server. This kind of communication should be repeatable many times using the same connection.
I write it like this:
// On a server:
ServerSocket serverSocket = new ServerSocket(port);
Socket socket = serverSocket.accept();
socket.setKeepAlive(true);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
if (reader.ready()) {
for (String line = reader.readLine(); line != null; line = reader.readLine()) {
// do something with line
}
}
// On a client:
Socket socket = new Socket(host, port);
socket.setKeepAlive(true);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
writer.write("Some data from client to server");
writer.flush();
The problem is: I can't read on a server before I close OutputStream on a client. Or I can't open OutputStream on a client again, if it was already closed. How can I do continuous sending and reading of data?
You need two threads at both ends, one for reading data and other one for writing data.
The problem is: I can't read on a server before I close OutputStream on a client.
Yes you can. You just can't get to the case where readLine() returns null. It isn't the same thing.
Or I can't open OutputStream on a client again, if it was already closed.
Of course not. You have to create a new Socket.
How can I do continuous sending and receiving of data?
I don't understand the question. The code you posted doesn't attempt that.
If your goal is to send many mesages over the same socket connection, these messages will have to be delimited by an application-level protocol. In other words, you won't be able to rely on any system calls like reader.ready() or reader.readLine() == null to detect the end of the message on te server.
One way to achieve this is to begin each message with its length in characters. The server will then read exactly that number of charecters, and then stop and wait for a new message. Another is to define a special character sequence which concludes each message. The server will react to reading that particular sequence by ending the reading of the current message and returning to the "wait for new message" state. You must ensure that this sequence never appears in the message itself.
I am using the below code to send data to a tcp server. I am assuming that I need to use socket.shutdownOutput() to properly indicate that the client is done sending the request. Is my assumption correct? If not please let me know the purpose of shutdownOutput(). Also appreciate any further optimizations I can make.
Client
def address = new InetSocketAddress(tcpIpAddress, tcpPort as Integer)
clientSocket = new Socket()
clientSocket.connect(address, FIVE_SECONDS)
clientSocket.setSoTimeout(FIVE_SECONDS)
// default to 4K when writing to the server
BufferedOutputStream outputStream = new BufferedOutputStream(clientSocket.getOutputStream(), 4096)
//encode the data
final byte[] bytes = reqFFF.getBytes("8859_1")
outputStream.write(bytes,0,bytes.length)
outputStream.flush()
clientSocket.shutdownOutput()
Server
ServerSocket welcomeSocket = new ServerSocket(6789)
while(true)
{
println "ready to accept connections"
Socket connectionSocket = welcomeSocket.accept()
println "accepted client req"
BufferedInputStream inFromClient = new BufferedInputStream(connectionSocket.getInputStream())
BufferedOutputStream outToClient = new BufferedOutputStream(connectionSocket.getOutputStream())
ByteArrayOutputStream bos=new ByteArrayOutputStream()
println "reading data byte by byte"
byte b=inFromClient.read()
while(b!=-1)
{
bos.write(b)
b=inFromClient.read()
}
String s=bos.toString()
println("Received request: [" + s +"]")
def resp = "InvalidInput"
if(s=="hit") { resp = "some data" }
println "Sending resp: ["+resp+"]"
outToClient.write(resp.getBytes());
outToClient.flush()
}
I am using the below code to send data to a tcp server. I am assuming
that I need to use socket.shutdownOutput() to properly indicate that
the client is done sending the request. Is my assumption correct?
YES Your assumption is correct. And this output ShutDown is known as half close . Using half close the TCP provides the ability for one end of the connection to terminate its output, while still receiving data from the other end. Let me walk you through the effects of socket.shutdownOutput() method :
Locally, the local socket and its input stream behave normally for reading
purposes, but for writing purposes the socket and its output stream behave
as though the socket had been closed by this end: subsequent writes to the
socket will throw an IOException
TCP’s normal connection-termination sequence (a - FIN acknowledged by
an ACK) is queued to be sent after any pending data has been sent and acknowledged.
Remotely, the remote socket behaves normally for writing purposes, but for
reading purposes the socket behaves as though it had been closed by this
end: further reads from the socket return an EOF condition, i.e. a read count
of -1 or an EOFException , depending on the method being called.
When the local socket is finally closed, the connection-termination sequence
has already been sent, and is not repeated; if the other end has already
done a half-close as well, all protocol exchanges on the socket are now
complete.
Hence we see that When the EOF is received, that end is assured that the other end has done the output shutdown. And this scenario is perfectly achieved by socket.shutDownOutput() on the other side.
Source: Fundamental Networking in Java, Esmond Pitt
Socket.shutdownOutput() means that the client is finished sending any data through the TCP connection. It will send the remaining data followed by a termination sequence which will completely close its OUTGOING connection. It is not possible to send any further data, which will also indicate to your program that the request is completely finished. So its recommended if you are sure you don't have to send any more data.
But it's not needed to indicate that the request is finished (you don't have to open/close the output all the time if you have multiple requests), there are other ways.
i have a txt file with students name and marks for subjects. i send this file from client to server using
Socket clientSocket = new Socket("127.0.0.1",5432);
OutputStream os = clientSocket.getOutputStream();
os.write(clientWriteArr,0,clientWriteArr.length);
and read this file at server using
ServerSocket sock = new ServerSocket(5432);
Socket serverSocket = sock.accept();
InputStream is = serverSocket.getInputStream();
is.read(serverReadArr,0,serverReadArr.length);
i am modifying the file contents upto this all is working fine.
after this i want to send back this file back to client but i am not getting file at the client and also not getting any exception
You can leave the original socket open from which you read the file, and then write the result to the same socket before closing it. This would be a standard request/response model like what is used for HTTP, and is convenient because the server does not need to know how to connect back to the client. Give us some code for more detailed advice.
You need the the "server" to open a socket connection back to the "client" to send data back. The "client" has to be listening on the port that the "server" wants to connect to.
"Client" and "server" have dual roles in this case.
What exception do you get?
Your server side code should be like:
ServerSocket serverSocket = new ServerSocket(8999);
Socket socket = serverSocket.accept();
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
Here, in : you can read the data sent by client.
out: you can write data to client
Your client code should be like:
Socket socket = new Socket("localhost", 8999);
DataInputStream in = new DataInputStream(socket.getInputStream());
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
Here, in you can send data to server.
out, you can read the data sent by server.
Reading data from input stream:
while (true) {
int c = in.read();
}
when you call in.read(), it will block current thread until it reads something.
Writing data to output stream:
out.write(data);