i tried to use this code but when i start the connection it seems that the server doesn't receive the string(the command):
public static void sendMessage(TelnetClient s, String myMessageString)
throws IOException {
OutputStream os = s.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(os);
oos.writeObject(myMessageString);
}
i tried also to use only the outputstream and to do the following thing:
os.write(myMessageString.getbytes());
You definitely don't want to use ObjectOutputStream - that will use binary serialization that your telnet server won't be expecting.
It would be best to create an OutputStreamWriter:
// Adjust the encoding to whatever you want, but you need to decide...
Writer writer = new OutputStreamWriter(s.getOutputStream(), "UTF-8");
writer.write(myMessageString);
writer.flush();
The flush call may well be what was missing before - depending on exactly what TelnetClient does, it may be buffering the data until you flush the stream.
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.
I'm writing a java server for an assignment, and I have observed some strange behaviour when I write both into a wrapped stream and a wrapper stream, can this cause any problems ? As far as I see, it can, but how ? Pls enlighten me.
as an example:
OutputStream os = new OutputStream(...);
PrintWriter pw = new PrintWriter(os);
And I want to write both in the PrintWriter, and the OutputStream.
To transfer from byte-based stream to character-based stream, you need to use OutputStreamWriter:
An OutputStreamWriter is a bridge from character streams to byte streams.
So that would be:
OutputStream os = ...
OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
PrintWriter pw = new PrintWriter(osw);
I think the problem is that you need to specify the encoding, since the constructor PrintWriter(OutputStream out) uses the default encoding which might not be correct for your data input:
OutputStream os = ...
PrintWriter pw = new PrintWriter(os, "UTF-8");
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.
when using TCP Socket I/O code.. Is there any big difference of performance between below two codes..?? The result of both is the same~~
// -------- 1 -------- //
OutputStream out = sock.getOutputStream();
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
// -------- 2 -------- //
OutputStream out = sock.getOutputStream();
PrintWriter pw = new PrintWriter(out);
No, it shouldn't be. Quoting the doc:
public PrintWriter(OutputStream out, boolean autoFlush)
Creates a new PrintWriter from an existing OutputStream. This convenience constructor creates the necessary intermediate OutputStreamWriter, which will convert
characters into bytes using the default character encoding.
In other words, a fresh OutputStreamWriter object is created in both cases of yours.
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.