Is it possible to send a TreeMap (containing keys and values) over a socket from server to client?
Writing to a socket is no different than writing to a file. The ObjectOutputStream class abstracts that layer for us. So you can test that your Serialization is working smoothly with file IO; then it is very easy to write to a Socket.
First Step: Test Your Serialization
TreeMap<YourKeyClass, YourValueClass> treeMap =
new TreeMap<>();
buildMyTree(treeMap);
FileOutputStream fout = new FileOutputStream("path/to/your/file.ser");
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(treeMap);
Second Step: Test Your Deserialization
Read your object back to check deserialization:
FileInputStream fin = new FileInputStream("path/to/your/file.ser");
ObjectInputStream ois = new ObjectInputStream(fin);
TreeMap<YourKeyClass, YourValueClass> treeMapFromFile = ois.readObject();
TreeMap is Serializable. Everything runs perfectly fine, as long as YourValueClass does not have complex structure that hinders serialization. For instance you may have recursive references to other objects in your YourValueClass, in which case you have to work on your work on your own writeObject and readObject implementations for Serialization.
So a read and write check is very important to be sure everything runs according to your structure.
Third Step: Move to Socket Programming
Once you are sure your serialization is working, move to socket programming. It is very important that you're confident that your serialization is working perfectly, before moving on to the socket, since if you miss a point on serialization then if anything fails during socket implementation, it will be very hard to find where the problem is.
Server Side:
//initialize your socket
//start listening on your socket
TreeMap<YourKeyClass, YourValueClass> treeMap = new TreeMap<>();
buildMyTree(treeMap);
ObjectOutputStream oos = new ObjectOutputStream(socketToClient.getOutputStream());
oos.writeObject(treeMap);
Client Side:
//initialize your socket
ObjectInputStream ios = new ObjectInputStream(socketToServer.getInputStream());
TreeMap<YourKeyClass, YourValueClass> treeMapFromSocket = ois.readObject();
You can use refer to the following sources:
Serialization
Oracle Tutorial for Java Socket Prog
ServerSocketChannel
Yes, it's possible.
java.util.TreeMap implements interface java.io.Serializable.
Also all of keys and values int TreeMap must implements this interface.
Related
I'm doing a comparison between some C functions used in network programming, and their Java counterpart. Most of them I can find in documents about Socket, ServerSocket, InetAddress classes.
However I can't seem to find listen(), recv(), send() and getaddrinfo() in Java. As far as I go, I see that most Java client-server programs do not require them, as you can just write the byte/message and flush them directly to the other end, using flush() or PrintWriter().
Do I understand this right, and are there any equivalent functions to those three?
When you create a ServerSocket, the underlying listen function gets called when you bind to a port, either through the constructor or though the bind method.
The recv and send functions are called by reading from and writing to the InputStream and OutputStream respectively that are attached to a Socket instance and returned by the getInputStream and getOutputStream methods.
Listening and receiving can be implemented in multiple different ways. Java is object-oriented so the logic is usually represented by a specific object type.
Take a look at Reading from and Writing to a Socket tutorial which gives a few examples on working with sockets, e.g. using InputStream and OutputStream to interact with Socket:
try (
Socket echoSocket = new Socket(hostName, portNumber);
PrintWriter out =
new PrintWriter(echoSocket.getOutputStream(), true);
BufferedReader in =
new BufferedReader(
new InputStreamReader(echoSocket.getInputStream()));
BufferedReader stdIn =
new BufferedReader(
new InputStreamReader(System.in))
)
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().
Suppose I want to send a collection of objects over a network via a socket in Java. For concreteness, suppose I want to send an array of BigInteger objects. The sender should simply send this array in one chunk over the socket, so that the receiver could cast the received object to the proper form.
How can this be accomplished ?
I've tried using ObjectOutputStream to send this array of objects. However, it doesn't go as planned.
Some of the code:
BigInteger[] bigIntegers = new BigInteger[10];
bigIntegers[0] = new BigInteger("0");
bigIntegers[1] = new BigInteger("1");
outputStream = new ObjectOutputStream(socket.getOutputStream());
outputStream.writeObject(bigIntegers);
I assume that the underlying architecture is the same at both ends.
Can someone show how to send such a collection of objects, as well as receive this collection on the other side of the socket?
Thanks,
you can send objects to server socket using
objectOut.writeObject(bigIntegers);
objectOut.flush();
and can retrieve that object at server side using
here client is clientsocket
ObjectInputStream objectIn = new ObjectInputStream(client.getInputStream());
BigInteger[] array = (BigInteger[]) objectIn.readObject();
I've started work on a simple newtworking project which creates a new thread for each connection and I'm trying to send multiple things across. What I'm wondering is there an easy way of simple say declaring a variable sending that whole variable to the server and that being sent to other clients. For example if I wanted to send a simple integer array? Basically how would I send an array or even an image across a socket?
Yes, it is possible. What you are looking for is called serialization and can be used to send entire objects through a stream (socket, file, etc.). Have a look at this java socket serialization tutorial.
Check the docs on ObjectOutpuStream and ObjectInputStream.
Basically what you have to do is have any custom type that you want to be serialized implement the Serializable interface:
class MyCustomType implements Serializable {
...
}
This is a marker interface that tells the runtime that this type can be sent over a stream.
Next, once your connections are set up you can obtain the socket input/output stream and write objects using ObjectOutputStream:
MyCustomType obj = new MyCustomType();
ObjectOutputStream oos = new ObjectOutputStream(client.getOutputStream());
oos.writeObject(obj);
oos.flush();
or read them using ObjectInputStream:
ObjectInputStream ois = new ObjectInputStream(client.getOutputStream());
MyCustomType obj = (MyCustomType) ois.readObject();
(client above is a Socket).
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.