send changed hashmap but get the same one using ObjectOutputStream and ObjectInputStream - java

public static void main(String[] args) throws Exception {
Socket socket = new Socket("127.0.0.1", 2345);
ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
Map<Integer, Integer> testMap = new HashMap<Integer, Integer>();
testMap.put(1,1);
oos.writeObject(testMap);
oos.flush();
testMap.put(2,2);
oos.writeObject(testMap);
oos.flush();
oos.close();
}
public static void main(String[] args) throws Exception {
ServerSocket ss = new ServerSocket(2345);
Socket s = ss.accept();
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
System.out.println((HashMap<Integer, Integer>) ois.readObject());
System.out.println((HashMap<Integer, Integer>) ois.readObject());
ois.close;
}
The code above is from two files.
When running them, the console prints the same result:
{1=1}
{1=1}
How can this happen?

An ObjectOutputStream remembers the objects it has written already and on repeated writes will only output a pointer (and not the contents again). This preserves object identity and is necessary for cyclic graphs.
So what your stream contains is basically:
HashMap A with contents {1:1}
pointer: "HashMap A again"
You need to use a fresh HashMap instance in your case.

As Thilo already said, an ObjectOutputStream keeps a cache of things it has written already. You can either use a fresh map as he suggests, or clear the cache.
Calling ObjectOutputStream.reset between the calls to writeObject will clear the cache and give you the behavior you originally expected.
public static void main(String[] args) throws IOException,
ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
HashMap<Integer, Integer> foo = new HashMap<>();
foo.put(1, 1);
oos.writeObject(foo);
// oos.reset();
foo.put(2, 2);
oos.writeObject(foo);
}
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
try (ObjectInputStream ois = new ObjectInputStream(bais)) {
System.out.println(ois.readObject());
System.out.println(ois.readObject());
}
}

Related

Java Encrypted Object Serialization through sockets

I'm trying to implement a method which provides data encryption using Object Serialization through Sockets (ObjectInputStream && ObjectOutputStream are used).
The aim here is to reduce everything to an array of byte data, which will be used as input for an encryption algorithm.
Here is a very rude code which i wrote to simply test and see how things work:
List<Byte> bytes=new LinkedList<>();
try (
ByteArrayOutputStream bos=new ByteArrayOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(bos);
InputStream finalInputStream=new InputStream() {
int counter=0;
#Override
public int read() throws IOException {
if (counter<bytes.size()) {
return bytes.get(counter++);
}
else return -1;
}
};
OutputStream finalOutputStream=new OutputStream() {
#Override
public void write(int b) throws IOException {
bytes.add((byte) b);
}
};
BufferedOutputStream bfos=new BufferedOutputStream(finalOutputStream);
BufferedInputStream bios=new BufferedInputStream(finalInputStream);
ObjectInputStream ois=new ObjectInputStream(bios);
){
oos.writeObject(new CryptoMain());
oos.flush();
bfos.write(bos.toByteArray());
CryptoMain obj=(CryptoMain)ois.readObject();
obj.printHello();
}
catch(Exception e) {
e.printStackTrace();
}
However i get EOFException at this statement:
ObjectInputStream ois=new ObjectInputStream(bios);
How can i obtain what i want? Is there an other way?
Thank you.
You don't need most of this.
You don't need both the ByteArrayOutputStream and the List<Byte> and the local InputStream class. You're doing everything three times. You don't actually need any of them.
There are several simple solutions:
javax.crypto.SealedObject
javax.crypto.CipherInput/OutputStream.
TLS.

Solving "socket is closed" exception while copying file from server to client and vice versa

I'm doing simple Client-Server applications which copying file from client to server and vice versa. I'm using Sockets of course. Apps shows Client menu with some options to choose: 1. Make Copy on sever 2. Get fileCopy from Server etc.
The issue is when I'm choosing first option, I can't do second one. I read about this exception, but i have no idea how to solve this problem. I'm looking forward for your ideas.
There is part of clientside code:
public Client(String host, int port) {
try {
s = new Socket(host, port);
System.out.println("Witaj w programie");
boolean finished = false;
Scanner sc = new Scanner(System.in);
while(!finished){
System.out.println("\n\n1.Zrob kopie zapasowa pliku");
System.out.println("2. Przywroc kopie");
System.out.println("0.Zakoncz");
char c = sc.nextLine().charAt(0);
switch(c){
case '1':
this.sendMessage(1);
makeCopy(s);
//s.close();
break; ...
sendMessage method code:
public void sendMessage(int message_id) throws IOException{
oos = new ObjectOutputStream(s.getOutputStream());
ois = new ObjectInputStream(s.getInputStream());
oos.writeInt(message_id);
oos.flush();
}
and makeCopy method code:
private void makeCopy(Socket clientSock) throws IOException {
File file = new File("D:\\klient\\doKopii.bmp");
DataOutputStream dos = new DataOutputStream(clientSock.getOutputStream());
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[4096];
while (fis.read(buffer) > 0) {
dos.write(buffer);
}
fis.close();
dos.close();
}
Download copy from Server code:
private void saveFile(Socket clientSock) throws IOException {
//DataInputStream dis = new DataInputStream(clientSock.getInputStream());
FileOutputStream fos = new FileOutputStream("D:\\klient\\przywroconaKopia.bmp");
File zSerwera = new File("D:\\serwer\\kopiaPliku.bmp");
byte[] buffer = new byte[4096];
int filesize = (int)zSerwera.length();
int read = 0;
int totalRead = 0;
int remaining = filesize;
while((read = ois.read(buffer, 0, Math.min(buffer.length, remaining))) > 0) {
totalRead += read;
remaining -= read;
System.out.println("read " + totalRead + " bytes.");
fos.write(buffer, 0, read);
}
//fos.close();
//ois.close();
}
I am aware of that this does not work because of DataOutputStream closing which means socket is also closed. I deleted this line, but after choosing one option then second (when first one has done), application just freezes.
oos = new ObjectOutputStream(s.getOutputStream());
ois = new ObjectInputStream(s.getInputStream());
public void sendMessage(int message_id) throws IOException{
oos.writeInt(message_id);
}
make oos and ois as instance variables and make sure that they are instantiated only for one single time.
why you have to get a dataoutput stream seperately you can send byte array in same objectoutputstream
private void makeCopy(Socket clientSock) throws IOException {
File file = new File("D:\\klient\\doKopii.bmp");
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[4096];
while (fis.read(buffer) > 0) {
oos.write(buffer);
}
}
this is not very good coding practise bt maybe u should try this approach
There are several problems here.
You need to send the file length ahead of the file, and read exactly that many bytes at the receiver, as shown in this answer.
Don't mix stream types, and don't keep creating new streams. Use the same ObjectInputStream/ObjectOutputStream pair for the life of the socket, at both ends.

Serialization issues

public void writeObject(String outFile) {
try {
FileOutputStream fos = new FileOutputStream(outFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
Student[] copy = this.getStudents();
for (Student st : copy){
oos.writeObject(st);}
oos.close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
The code above is the function I use to serialize the contents of my repository,getStudens() is returning an array of my data.
public void readSerialized(String fileName) throws Exception {
FileInputStream fis = new FileInputStream(fileName);
ObjectInputStream ois = new ObjectInputStream(fis);
while(fis.available()>0){
ctrl.addC((Student) ois.readObject());}
ois.close();
}
This my deserialization function which should recreate my data and add it again in my repository.The problem is that it doesn't recreate the data I had in my repository when I serialized it first.
What I had in repository before serialization:
1 a 4.0 6.0
2 b 10.0 10.0
3 c 2.0 2.0
4 d 8.0 2.0
5 e 6.0 2.0
What the deserialization returns:
0 3.0
0 5.0
Does this means that my serialization function isn't correct or something goes wrong when I deserialize?
Your code is needlessly complicated and using available() is always rather confusing I find. It means you can read without a system call it doesn't mean there is nothing left.
I suggest just serializing the array.
FileOutputStream fos = new FileOutputStream(outFile);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(this.getStudents());
oos.close();
FileInputStream fis = new FileInputStream(fileName);
ObjectInputStream ois = new ObjectInputStream(fis);
Student[] copy = (Student[]) ois.readObject();
ois.close();
In Java, arrays are objects too.

Regarding serializing the array list object

I have an array list that I want to serialize please advise how to I will be able to do that..
ArrayList list=new ArrayList();
list.add("Ram");
list.add("Sachin");
list.add("Dinesh");
list.add(1,"Ravi");
list.add("Dinesh");
list.add("Anupam");
System.out.println("There are "+list.size()+" elements in the list.");
System.out.println("Content of list are : ");
Iterator itr=list.iterator();
while(itr.hasNext())
System.out.println(itr.next());
}
}
I want to use the serialization mechanism so that I can save it in file
It is very simple. Both ArrayList and String (that you store in the list) implement Serializable interface, so you can use the standard java mechanism for serialization:
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("myfile"));
oos.writeObject(list);
............
oos.fluch();
oos.close();
In this example I wrapped FileOutputStream with ObjectOutputStream but obviously you can use any other payload stream.
You have to create your own methods for serializing and deserializing objects. The below are useful methods for doing just that.
public static Object deserializeBytes(byte[] bytes) throws IOException, ClassNotFoundException
{
ByteArrayInputStream bytesIn = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bytesIn);
Object obj = ois.readObject();
ois.close();
return obj;
}
public static byte[] serializeObject(Object obj) throws IOException
{
ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bytesOut);
oos.writeObject(obj);
oos.flush();
byte[] bytes = bytesOut.toByteArray();
bytesOut.close();
oos.close();
return bytes;
}

Can I change the type of stream I'm using without closing and reopening the socket in Java?

I'm doing some socket programming in Java and I'd like to be able to change between using the ObjectOutputStream, the DataOutputStream, and the PrintWriter all within the same socket/connection. Is this possible and what is the best way to do it?
I've tried just creating both types of objects, for example ObjectOutputStream and DataOutputStream, but that doesn't seem to work.
The reason I want to switch between them is to, for example, send a text command "INFO" that signals I'm about to send an object with information or a command "DATA" signalling that I'm about to send data. Any advice on the best way to do this is appreciated.
You can only use one underlying stream type however you can get that data from anywhere.
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(s.getOutputStream()));
public static void writeObject(DataOutputStream dos, Serializable obj) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(obj);
oos.close();
dos.writeUTF("OBJECT");
byte[] bytes = baos.toByteArray();
dos.writeInt(bytes.length);
dos.write(bytes);
dos.flush();
}
public static void writeBytes(DataOutputStream dos, byte[] bytes) {
dos.writeUTF("BYTES");
dos.writeInt(bytes.length);
dos.write(bytes);
dos.flush();
}
public static void writeText(DataOutputStream dos, String text) {
dos.writeUTF("TEXT");
dos.writeUTF(text);
dos.flush();
}
Why do you want the *Stream to convert to the *Writer.
You can do what you want to do with *Stream.
Socket s = new Socket();
DataOutputStream stream = new DataOutputStream( s.getOutputStream() );
byte[] bytes = "INFO".getBytes();
stream.write(bytes);
//....
bytes = "DATA".getBytes();
stream.write(bytes);

Categories

Resources