I have a client class and a server class. There is a client method which I use to call the server and my code hangs if I try use this method more than once during a jvm session.
Client code's main method:
methodA();
methodA();
ois.close(); //ObjectInputStream
oos.close(); //ObjrctOutputStream
is.close(); //InputStream
os.close(); //OutputStream
socket.close();
Client code's methodA() looks like this:
os = socket.getOutputStream();
oos = new ObjectOutputStream(os);
oos.writeObject(obj);
is = socket.getInputStream();
ois = new ObjectInputStream(is);
Object o = ois.readObject();
Server code's main method looks like:
while (true) {
Socket socket = serverSocket.accept();
is = socket.getInputStream();
ois = new ObjectInputStream(is);
Object o = ois.readObject();
servermethod();
}
oos.close();
ois.close();
is.close();
os.close();
serverSocket.close();
The server's serverMethod() looks like:
os = socket.getOutputStream();
oos = new ObjectOutputStream(os);
Object ob = getObject() ; //this method is working fine
oos.writeObject(ob);
What I wanted to do was to have the client call the server a few times using methodA(). I might not be handling the streams correctly. Any help?
There are definitely a few things wrong with this code:
You are creating ObjectInputStream and ObjectOutputStream repeatedly on top of the same streams. This is not how how they are supposed to be used. What you are supposed to do is create the ObjectXxxStream once, and then call readObject or writeObject multiple times on the same ObjectXxxStream. If you are sending the same object multiple times, you need to call reset before writing the object again.
You are not flushing the streams. If you don't flush after writing, there is no guarantee that the serialized representation will get sent to the other end ... where something is waiting for the bytes to arrive.
Your server end code is written in a way to read only one object and write only one object to a newly created Socket. Hence you try to reuse the Socket a second or nth time, it doesn't get back a response from the server. There are 2 ways to fix it.
You can fix on the server end : This will be an elaborate change, but better use of resources. You don't stop reading the stream until it is closed.
You fix it in the client end : Instead of creating the Socket outside the main method, you create the Socket inside MethodA(). Easy and dirty solution though.
Related
I have the following code that works (please assume that hostname and port are initialized to their proper values, and that Message is a serializable class):
//Example 1 - everything works as expected
Message message = new Message();
try(Socket serverSocket = new Socket(hostname, port))
{
ObjectOutputStream outStream = new ObjectOutputStream(serverSocket.getOutputStream());
outStream.writeObject(message);
outStream.flush();
ObjectInputStream inStream = new ObjectInputStream(serverSocket.getInputStream());
Object response = inStream.readObject();
}
When I move the instantiation of the ObjectInputStream to occur immediately after the ObjectOutputStream instantiation, execution of my application hangs indefinitely:
//Example 2 - client locks up
Message message = new Message();
try(Socket serverSocket = new Socket(hostname, port))
{
ObjectOutputStream outStream = new ObjectOutputStream(serverSocket.getOutputStream());
ObjectInputStream inStream = new ObjectInputStream(serverSocket.getInputStream());
outStream.writeObject(message);
outStream.flush();
Object response = inStream.readObject();
}
I'm looking for a good explanation as to why the second example locks up consistently, and the first example seems to work without a hitch. Strangely, if I use a debugger (Eclipse debugger) on the client and server with this second example, I'm seeing the message make it through to the server, so the writeObject() call is being executed. However, in the client, the debugger gets stuck on the constructor for the ObjectInputStream.
If we go and have a read of the API docs for the ObjectInputStream constructor
The important part:
This constructor will block until the corresponding ObjectOutputStream
has written and flushed the header.
Constructing an ObjectOutputStream writes a header to the stream. Constructing an ObjectInputStream reads it. If both ends construct the ObjectInputStream first, you will therefore get a deadlock.
Solution: construct the ObjectOutputStream first, at both ends, to make sure it can't happen.
Based on the following information from my prof:
The client creates ObjectOutputStream and ObjectInputStream objects to send the request, and to receive the reply. The CalculateClient constructor is:
public CalculateClient( String host, int port )
throws IOException
{
/* determine the address of the server and connect to it */
serverHost = InetAddress.getByName( host );
serverPort = port;
calculate = new Socket( serverHost, serverPort );
OutputStream out = calculate.getOutputStream();
request = new ObjectOutputStream(
new BufferedOutputStream( out ));
request.flush();
// ObjectInputStream blocks until
// the connected side flushes its ObjectOutputStream
InputStream in = calculate.getInputStream();
reply = new ObjectInputStream( in );
}
In network applications, the construction order of the input and output socket streams when using object streams is important. The ObjectOutputStream must be created first. It then should be flushed. The ObjectInputStream can then be created.
He doesn't elaborate as to why. Why is this true?
It is explained in the comments of the code you posted, isn't it?
// ObjectInputStream blocks until
// the connected side flushes its ObjectOutputStream
So if you try to create the ObjectInputStream the constructor waits until the corresponding ObjectOutputStream's flush() method is called. Since you haven't created it yet, guess what happens?
As an alternative to asking this question, you could have simply switched the creation order and observed the results. It takes arguably less effort on your part and as a bonus you've learned how to problem-solve and think critically.
I did a Java Socket server, and a C++ Client.
However, the client connects to the server, without problems.
But when I write something client-server, the server doesn't catch the message.
What I'm doing wrong?
A little bit of the code of the Java Server:
DataInputStream dis=new DataInputStream(usrSocket.getInputStream());
ByteArrayOutputStream out = new ByteArrayOutputStream();
int data;
while((data = dis.read())>=0) {
out.write(data);
}
byte[] bytes = out.toByteArray();
String decrypt = new String(bytes);
if(decrypt.equals("status")){
System.out.println("Status emitted.");
}
System.out.println("Received a message.");
C++ Client writing:
QByteArray qba;
qba.append(text);
sock->write(qba.data());
qDebug() << "Send status";
I need help with that, thank you very much.
(that variable "text" it's a QString)
EDIT
Java server: That's only one part of all the code, the main thread waits for connections (Socket sock = server.accept()) and create a new thread for each user.
The code that I published of the java server, its one part of that threads for the users.
If you need ALL the code, plese tell me.
I will be waiting the answers!
Thank u very much!
Sorry if I answer ya late.
Try this code for Java Server.
ServerSocket ss = new ServerSocket(Port_No);
Socket incomingClient = ss.accept();
InputStream i = incomingClient.getInputStream();
OutputStream o = incomingClient.getOutputStream(); // Use it write to the Client Socket
InputStreamReader isr = new InputStreamReader(i);
BufferedReader br = new BufferedReader(isr);
String str = new String();
while ((str = br.readLine())!=null){
// do what you want with the data received in str.
}
As youre using QTcpSocket, it highly likely that you are running the client in the default asynchronous mode. This means after when you write after calling connectToHost, nothing will be sent as the socket is not connected.
Try using:
socket->connectToHost(hostAddress, hostPort, QIODevice::ReadWrite);
if (socket->waitForConnected()) {
QString text = "test string";
QByteArray array;
array.append(string);
qDebug() << socket->write(array);
} else {
// connect error!
}
Your Java code reads the socket until EOS and then prints something, which by the way is not a decryption operation. Your C++ client writes something and never closes the socket. So the server can never get out of the read loop.
If I read it correctly it is caused by the fact that your client is still running. Read() returns number >= 0 until the client socket is closed.
I am having trouble bouncing object between the client and the server.
Create an object. Update some fields. Send to Server. (this part works)
SomeObject thisObject = new SomeObject();
thisObject.setSomeValue(13); // update object to be sent
PrintStream toServer = new PrintStream(sock.getOutputStream());
ObjectOutputStream oos = new ObjectOutputStream(toServer);
oos.writeObject(thisObject);
oos.close();
toServer.println(oos); // send object to server
toServer.flush();
Right after this, server further updates some value and sets it to 1919;
ObjectInputStream objFromClient = new ObjectInputStream(new BufferedInputStream(
sock.getInputStream()));
Served thisObject = (Served) objFromClient.readObject();
thisObject.setSomeValue(1919);
Server then sends the object back to client
toClient = new PrintStream(sock.getOutputStream());
ObjectOutputStream oos = new ObjectOutputStream(toClient);
oos.writeObject(thisObject);
oos.close();
objFromClient.close();
sock.close();
But when the time comes to pick up the object back on the client side .. programs fails with Socket Closed exception
ObjectInputStream objFromServer = new ObjectInputStream(
new BufferedInputStream(sock.getInputStream())); //java.net.SocketException: Socket is closed
thisObject = (Served) objFromServer.readObject();
....
Please help me understand the issue
My guess is you're using the same Socket to both send and receive from the client. When you close the ObjectOutputStream on the client, this closes the underlying OutputStream, which closes sock. Then, when you try to reuse it below, it's been closed and throws an exception.
Instead, wait for the transaction to finish before closing your resources in the client code (which should be done in a finally block by the way). Or, if waiting is problematic, use a new Socket instead.
This is the code that i used on client socket
Socket connected = Server.accept();
ObjectOutputStream oos = new ObjectOutputStream(connected.getOutputStream());
oos.writeObject(dPFPSample.serialize());
This the code that i used on server socket
Socket clientSocket = new Socket("localhost", 5002);
ObjectInputStream ois = new ObjectInputStream(clientSocket.getInputStream());
DPFPSample dpfpSample = (DPFPSample) ois.readObject();
i got an error java.lang.ClassCastException exception on ois.readObject() line
I would assume that your DPFPSamle.serialize() returns something different then DPFPSamle. I'd say you don't need to call any serialization method. The stream will handle it. So just call writeObject(dPFPSample)
In order for this to work your class (the one you are trying to send - i.e. DPFPSample) must implement the java.io.Serializable interface.