i am having a very weird situation in my code which i dont understand i am sending an object lets say O through a socket then i am changing the value of a variable in the object and sending it again but the second time when i print it on the client side, i am getting the same values as in the 1st object.
client code:
while(true){
try{
order=(Order)ois.readObject();
System.out.println(order);
}
server code:
public void sendOrder(Order o){
try {
out.writeObject(o);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
main method:
Server_Socket ss=new Server_Socket();
ss.sendOrder(o);
o.add(r2);
ss.sendOrder(o);
The value is definitely changing on the serverside before i send it, but i dont understand why on the client side its not showing that r2 added in the object.
The objects are being cached by the ObjectOutputStream. To prevent this, call ObjectOutputStream.reset() after each write. If you are sending simple objects that don't contain other objects, use writeUnshared() instead of writeObject().
The objects are being cached by the IOStreams. To fix this, create a deep clone on the server prior to sending the object back. When the client pulls the object from the stream, it will have a different instance id and it will actually deserialize and instantiate the object on the client side.
Fun stuff.
Related
We're working on a school project where we have to use Telnet (Yes, I know, we shouldn't use it etc., but we have to) to communicate between a server and a client. We have two classes setup, a server and a client, which is a thread. We called our client 'NetManager', it can send and receive messages.
However, we have other classes as well which need to send messages to the server, and handle the output the server returns. We want to do this via the NetManager, instead of setting up a new Thread and socket for each class individually.
However, we do not know how to do this. Ideally we want to have a while(working) { } in our NetManager class which reads the lines the server sends, but we also need to send messages inside the while loop. The messages needs to vary so simply putting them in the while loop won't work. Is there a way to do server-client communication, where multiple classes use the NetManager class to send and receive messages from a server?
I have included a stripped down version of our NetManager class below for reference. This version only reads lines sent by the server, it does not yet send messages (which could be accomplished with out.println();
.
public class NetManager extends Thread {
private BufferedReader in;
private BufferedReader stdIn;
private PrintWriter out;
private String line;
#Override
public void run() {
boolean working = true;
try {
Socket sock = new Socket("localhost", 7789);
out = new PrintWriter(sock.getOutputStream(), true);
in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
while (working) {
try {
line = in.readLine();
System.out.println(line);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Here is a quick scheme I made of the best case scenario:
While I think your design is a good one I also think it may be overly complicated for what you are trying to do. If multiple classes are going to be using the same NetManager instance then you are going to have to implement some sort of locking and/or queuing so only one class tries to access NetManager at a time. Then you will also have to figure out some way to make sure any response received by NetManager gets back to the appropriate caller.
Having said all that, I would have any classes that use NetManager accept an instance of it in the constructor. It would then save a reference to the object and use it as necessary.
When we write REST client with jersey we should close Response like this:
Client c = ClientBuilder.newClient();
Response r = null;
try {
r = c.target("http://localhost:8080/testrest/customers/854878").request().get();
Customer cus = r.readEntity(Customer.class);
/* process result */
} catch (Exception e) {
/* log here */
if (r != null) {
r.close();
}
}
how should we access Response object when we directly read HTTP body:
Client c = ClientBuilder.newClient();
Customer cus = c.target("http://localhost:8080/testrest/customers/854878").request().get(Customer.class);
/* close Response object and process result */
Assuming you are using Glassfish's jersey-client implementation version 2.3.1 (or check the other versions too), you can follow the calls that get(Class) makes. A little down the line you will find a call to
org.glassfish.jersey.message.internal.InboundMessageContext#readEntity(Class<T>, Type, Annotation[], PropertiesDelegate)
which, based on some rules, closes the response
if (!buffered && !(t instanceof Closeable) && !(t instanceof Source)) {
entityContent.close(); // wrapper to the actual response stream
}
where t is the object created based on the specified Class object.
The API itself doesn't seem to say anything about this so an implementation doesn't have to close the underlying response stream. The only thing I could find is from Client javadoc which states
Client instances must be properly closed before being disposed to
avoid leaking resources.
So do not depend on a specific implementation, make sure to close everything yourself, even if that means you have to break your Fluent method invocations and store intermediate object references in variables.
Client has a close method. Look into its sources. If Client.close doesn't clean up its resources then you must obtain a reference to Response and close it. Otherwise you'll have hanging connections.
If code allows you to do something, it doesn't mean you should. But from your questions I gather that you understand it.
I saw plenty of similar questions on SO but hardly any of them have Socket in the picture. So please take time to read the question.
I have server app (using ServerSocket) which listens for requests, and when a client attempts to connect, new thread is created to serve the client (and server is back to listening mode for new requests). Now, I need to respond one client based on what other client sent to server.
Example:
ServerSocket listening for incoming connections.
Client A connects, new thread is created to serve A.
Client B connects, new thread is created to serve B.
A sends message "Hello from A" to the Server.
Send this message as a response to Client B.
I'm new to this whole "inter-thread communication" thing. Obviously, above mentioned situation sounds dead simple, but I'm describing this to get a hint, as I'll be exchanging huge amount data among clients keeping server as intermediate.
Also, what if I want to keep a shared object limited to, say 10, particular Clients? such that, when 11th client connects to the server, I create new shared object, which will be used to exchange data between 11th, 12th, 13th..... upto 20th client. And so on for every single set of 10 clients.
What I tried: (foolish I guess)
I have a public class with that object supposed to be shared as public static, so that I can use it as global without instantiating it, like MyGlobalClass.SharedMsg.
That doesn't work, I was unable to send data received in one thread to the other.
I'm aware that there is an obvious locking problem since if one thread is writing to an object, other can't be accessing it until the first thread is done writing.
So what would be an ideal approach to this problem?
Update
Since the way in which I create threads for serving incoming connection requests, I can't understand how I can share same object among the threads, since using Global object as mentioned above doesn't work.
Following is how I listen for incoming connections and create serving threads dynamically.
// Method of server class
public void startServer()
{
if (!isRunning)
{
try
{
isRunning = true;
while (isRunning)
{
try
{
new ClientHandler(mysocketserver.accept()).start();
}
catch (SocketTimeoutException ex)
{
//nothing to perform here, go back again to listening.
}
catch (SocketException ex)
{
//Not to handle, since I'll stop the server using SocketServer's close() method, and its going to throw SocketException anyway.
}
}
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
else
System.out.println("Server Already Started!");
}
And the ClientHandler class.
public class ClientHandler extends Thread
{
private Socket client = null;
private ObjectInputStream in = null;
private ObjectOutputStream out = null;
public ClientHandler(Socket client)
{
super("ClientHandler");
this.client = client;
}
//This run() is common for every Client that connects, and that's where the problem is.
public void run()
{
try
{
in = new ObjectInputStream(client.getInputStream());
out = new ObjectOutputStream(client.getOutputStream());
//Message received from this thread.
String msg = in.readObject().toString();
System.out.println("Client # "+ client.getInetAddress().getHostAddress() +" Says : "+msg);
//Response to this client.
out.writeObject("Message Received");
out.close();
in.close();
client.close();
}
catch (Exception ex)
{
ex.printStackTrace();
}
}
}
I believe that the way I'm creating dynamic threads to serve each client that connects, sharing the same data source is not possible using Global object, since the body of run() above is exactly the same for every client that connects, hence this same method is both consumer and producer. What fixes should I make such that I could create dynamic threads for each connection and still share the same object.
You probably want a queue for communication between each client. Each Queue will be the 'pipeline' for data pushed from one client to the other.
You would use it like so (pseudo code):
Thread 1:
Receive request from Client A, with message for Client B
Put message on back of concurrent Queue A2B
Respond to Client A.
Thread 2:
Receive request from Client B.
Pop message from front of Queue A2B
Respond to Client B with message.
You might also want it generic, so you have a AllToB Queue that many clients (and thus many threads) can write to.
Classes of note: ConcurrentLinkedQueue, ArrayBlockingQueue.
If you want to limit the number of messages, then ArrayBlockingQueue with its capacity constructor allows you to do this. If you don't need the blocking functionality, you can use the methods offer and poll rather than put and take.
I wouldn't worry about sharing the queues, it makes the problem significantly more complicated. Only do this if you know there is a memory usage problem you need to address.
EDIT: Based on your update:
If you need to share a single instance between all dynamically created instances you can either:
Make a static instance.
Pass it into the constructor.
Example of 1:
public class ClientHandler extends Thread
{
public static final Map<ClientHandler, BlockingQueue<String>> messageQueues
= new ConcurrentHashMap<>();
<snip>
public ClientHandler(Socket client)
{
super("ClientHandler");
this.client = client;
// Note: Bad practice to reference 'this' in a constructor.
// This can throw an error based on what the put method does.
// As such, if you are to do this, put it at the end of the method.
messageQueues.put(this, new ArrayBlockingQueue<>());
}
// You can now access this in the run() method like so:
// Get messages for the current client.
// messageQueues.get(this).poll();
// Send messages to the thread for another client.
// messageQueues.get(someClient).offer(message);
A couple of notes:
The messageQueues object should really contain some sort of identifier for the client rather than an object reference that is short lived.
A more testable design would pass the messageQueues object into the constructor to allow mocking.
I would probably recommend using a wrapper class for the map, so you can just call offer with 2 parameters rather than having to worry about the map semantics.
This is an example of a user defined class I'd like to send from a client application to a server application:
class dataStruct implements Serializable{
byte data;
int messageNum;
public void setData(byte datum, int messageNumber){
data=datum;
messageNum=messageNumber;
}
}
How do you send a user defined class over a tcp/ip connection in java?
What types of streams can I use to accomplish this (if I'm sending more than just text)?
Can I pass a full object via a socket stream, or will I always have to cast it after it has been passed via a stream?
I'm writing a server/client application, and I've only been able to find tutorials with examples of primitive types or strings being passed over a network connection - not user defined types.
Your help and direction are greatly appreciated.
Use an ObjectOutputStream on the sending side and an ObjectInputStream on the receiving side.
To be a bit more clear, here is an example (without any exception handling).
sending side:
dataStruct ds = ...;
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(ds);
oos.close();
receiving side:
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Object o = ois.readObject();
if(o instanceof dataStruct) {
dataStruct ds = (dataStruct)o;
// do something with ds
}
else {
// something gone wrong - this should not happen if your
// socket is connected to the sending side above.
}
So yes, you have to cast at the receiving side so the compiler knows the right class. (The casting does not change the class of the object, only changes the compiler's knowledge of it.)
This Serialization is also usable to save objects to a file.
Of course, this gives only interoperability to Java, if you have a non-Java partner, you might want to use a custom serialization protocol, or some XML-based format.
Let the objects implement the Serializable marker interface, and then transfer the objects using ObjectOutputStream and ObjectInputStream. When the object comes out on the other end, it will be via the readObject() method on ObjectInputStream, which returns Object, so yes, you will need to cast it to the proper type.
I have a client Server application which communicate using objects.
when I send only one object from the client to server all works well.
when I attempt to send several objects one after another on the same stream I get
StreamCorruptedException.
Can some one direct me to the cause of this error?
client write method
private SecMessage[] send(SecMessage[] msgs)
{
SecMessage result[]=new SecMessage[msgs.length];
Socket s=null;
ObjectOutputStream objOut =null;
ObjectInputStream objIn=null;
try
{
s=new Socket("localhost",12345);
objOut=new ObjectOutputStream( s.getOutputStream());
for (SecMessage msg : msgs)
{
objOut.writeObject(msg);
}
objOut.flush();
objIn=new ObjectInputStream(s.getInputStream());
for (int i=0;i<result.length;i++)
result[i]=(SecMessage)objIn.readObject();
}
catch(java.io.IOException e)
{
alert(IO_ERROR_MSG+"\n"+e.getMessage());
}
catch (ClassNotFoundException e)
{
alert(INTERNAL_ERROR+"\n"+e.getMessage());
}
finally
{
try {objIn.close();} catch (IOException e) {}
try {objOut.close();} catch (IOException e) {}
}
return result;
}
server read method
//in is an inputStream Defined in the server
SecMessage rcvdMsgObj;
rcvdMsgObj=(SecMessage)new ObjectInputStream(in).readObject();
return rcvdMsgObj;
and the SecMessage Class is
public class SecMessage implements java.io.Serializable
{
private static final long serialVersionUID = 3940341617988134707L;
private String cmd;
//... nothing interesting here , just a bunch of fields , getter and setters
}
If you are sending multiple objects, it's often simplest to put them some kind of holder/collection like an Object[] or List. It saves you having to explicitly check for end of stream and takes care of transmitting explicitly how many objects are in the stream.
EDIT: Now that I formatted the code, I see you already have the messages in an array. Simply write the array to the object stream, and read the array on the server side.
Your "server read method" is only reading one object. If it is called multiple times, you will get an error since it is trying to open several object streams from the same input stream. This will not work, since all objects were written to the same object stream on the client side, so you have to mirror this arrangement on the server side. That is, use one object input stream and read multiple objects from that.
(The error you get is because the objectOutputStream writes a header, which is expected by objectIutputStream. As you are not writing multiple streams, but simply multiple objects, then the next objectInputStream created on the socket input fails to find a second header, and throws an exception.)
To fix it, create the objectInputStream when you accept the socket connection. Pass this objectInputStream to your server read method and read Object from that.
when I send only one object from the client to server all works well.
when I attempt to send several objects one after another on the same stream I get StreamCorruptedException.
Actually, your client code is writing one object to the server and reading multiple objects from the server. And there is nothing on the server side that is writing the objects that the client is trying to read.
This exception may also occur if you are using Sockets on one side and SSLSockets on the other. Consistency is important.