I need to send a message from the ServerSocket to the client when the key is writable, I think that the message is being sent in the right way but when I try to read it on the client I get this error:
java.io.StreamCorruptedException: invalid stream header: 48656C6C
at java.io.ObjectInputStream.readStreamHeader(ObjectInputStream.java:866)
at java.io.ObjectInputStream.<init>(ObjectInputStream.java:358)
at MyTcpClient.main(MyTcpClient.java:22)
How can I read the message correctly in the client? These are my files:
MyAsyncProcessor.java
import java.io.IOException;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MyAsyncProcessor {
HashMap<Integer, MyTask> hashMap = new HashMap<>();
ExecutorService pool;
public MyAsyncProcessor() {
}
public static void main(String[] args) throws IOException {
new MyAsyncProcessor().process();
}
public void process() throws IOException {
pool = Executors.newFixedThreadPool(2);
InetAddress host = InetAddress.getByName("localhost");
Selector selector = Selector.open();
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
serverSocketChannel.bind(new InetSocketAddress(host, 9876));
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
SelectionKey key;
System.out.println("AsyncProcessor ready");
while (true) {
if (selector.select() > 0) {
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> i = selectedKeys.iterator();
while (i.hasNext()) {
key = i.next();
if (!key.isValid()) {
key.cancel();
continue;
}
if (key.isAcceptable()) {
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
System.out.println("Channel hashCode: " socketChannel.hashCode());
MyTask task = new MyTask(selector, socketChannel);
hashMap.put(socketChannel.hashCode(), task);
pool.execute(task);
socketChannel.register(selector, SelectionKey.OP_READ);
}
if (key.isReadable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
MyTask task = hashMap.get(socketChannel.hashCode());
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
try {
socketChannel.read(byteBuffer);
String result = new String(byteBuffer.array()).trim();
String[] words = result.split(" ");
task.timeToRead = Integer.parseInt(words[words.length - 2]) * 1000;
task.timeToWrite = Integer.parseInt(words[words.length - 1]) * 1000;
System.out.println(Thread.currentThread().getName() " reads for " task.timeToRead " mills");
try {
Thread.sleep(task.timeToRead);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() " ended reading");
} catch (Exception e) {
e.printStackTrace();
return;
}
socketChannel.register(selector, SelectionKey.OP_WRITE);
}
if (key.isWritable()) {
SocketChannel socketChannel = (SocketChannel) key.channel();
MyTask task = hashMap.get(socketChannel.hashCode());
task.readyToWrite();
hashMap.remove(socketChannel.hashCode());
System.out.println(Thread.currentThread().getName() " writes for " task.timeToWrite " mills");
try {
Thread.sleep(task.timeToWrite);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() " ended writing");
CharsetEncoder enc = StandardCharsets.US_ASCII.newEncoder();
String response = "Hello!\n";
socketChannel.write(enc.encode(CharBuffer.wrap(response)));
key.cancel();
}
i.remove();
}
}
}
}
}
MyTcpClient.java
import java.io.*;
import java.net.Socket;
import java.util.Random;
public class MyTcpClient {
public static void main(String[] args) {
Random rand = new Random();
int secondsToRead = rand.nextInt(5);
int secondsToWrite = secondsToRead 1;
String message = "Seconds for the task to be read and written: " secondsToRead " " secondsToWrite;
System.out.println(message);
Socket socket;
ObjectInputStream ois;
try {
socket = new Socket("127.0.0.1", 9876);
PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);
printWriter.println(message);
System.out.println("Sending message");
ois = new ObjectInputStream(socket.getInputStream());
String response = (String) ois.readObject();
System.out.println("Response: " response);
ois.close();
} catch (IOException e) {
System.out.println("Error in Socket");
e.printStackTrace();
System.exit(-1);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
Thank you in advance
CodePudding user response:
Here on the server you are sending raw (text) data
socketChannel.write(enc.encode(CharBuffer.wrap(response)));
And here on the client you are trying to read this as an Object
ois = new ObjectInputStream(socket.getInputStream());
String response = (String) ois.readObject();
System.out.println("Response: " response);
For your ObjectInputStream to work, you need to be using an ObjectOutputStream on the other side. I would recommend against using the Object streams, as these are Java-only and can fail if the two sides are using different versions of the serialized object. Instead, just use raw streams.
Better yet, use WebSockets
- WebSockets handle a lot of the plumbing that sockets come with in a more elegant way. You can definitely find an implementation of WebSockets for Java on GitHub
CodePudding user response:
I have solved it by using on the client to receive:
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
server.read(readBuffer);
String result = new String(readBuffer.array()).trim();
In the server to send:
CharsetEncoder enc = StandardCharsets.US_ASCII.newEncoder();
String response = "Task completed in " (this.timeToWrite this.timeToRead) " mills \n";