Sending message between ServerSocket and client - java

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

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

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";

Related

SocketChannel. invalid stream header: 00000000

I want to serialize 'Message' object, I can successfully transfer it as bytes array through socketChannel. After that, I change the object's properties (so that it may have larger size), and then there's a problem in sending object back to the client.
Once I try to obtain the object on the client side, I get an exception, it occurs when I deserealize Message obj in getResponse() method:
org.apache.commons.lang3.SerializationException: java.io.StreamCorruptedException: invalid stream header: 00000000
But, somehow, this applies only for the first client (After the exception is thrown, connection with the first client is over) and when I start a new client (not closing server) I can successfully transfer the object back and forth, furthermore, it works for any new clients.
This is my minimal debuggable version:
import org.apache.commons.lang3.SerializationUtils;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
public class Client {
private SocketChannel server;
public void start() throws IOException {
try {
server = SocketChannel.open(new InetSocketAddress("localhost", 5454));
server.configureBlocking(false);
} catch (IOException e) {
System.err.println("Server isn't responding");
System.exit(0);
}
Scanner scRequest = new Scanner(System.in);
Scanner scState = new Scanner(System.in);
System.out.println("Enter request:");
String request = scRequest.nextLine();
while (!request.equals("exit")) {
try {
// In my actual project class Person is a way different (But it's still a POJO)
// I included it here to make sure I can get it back after sending to the server
System.out.println("Enter a number:");
Person person = new Person(scState.nextInt());
sendRequest(request, person);
System.out.println("\nEnter request:");
request = scRequest.nextLine();
} catch (Exception e) {
e.printStackTrace();
}
}
stop();
}
public void sendRequest(String sMessage, Person person) {
Message message = new Message(sMessage, person);
ByteBuffer requestBuffer = ByteBuffer.wrap(SerializationUtils.serialize(message));
try {
server.write(requestBuffer);
requestBuffer.clear();
getResponse();
} catch (Exception e) {
System.out.println(e.getMessage());
System.err.println("Connection lost");
System.exit(0);
}
}
public void getResponse() throws Exception {
ByteBuffer responseBuffer = ByteBuffer.allocate(1024 * 1024 * 64);
int read = server.read(responseBuffer);
responseBuffer.clear();
if(read == -1) {
throw new Exception();
}
byte[] bytes = new byte[responseBuffer.limit()];
responseBuffer.get(bytes);
Message message = SerializationUtils.deserialize(bytes);
System.out.println(message);
}
public void stop() throws IOException {
server.close();
}
public static void main(String[] args) throws IOException {
Client client = new Client();
client.start();
}
}
import org.apache.commons.lang3.SerializationUtils;
import java.io.*;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class Server {
public void start() throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress("localhost", 5454));
serverSocket.configureBlocking(false);
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started");
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
register(selector, serverSocket);
}
if (key.isReadable()) {
try {
getRequest(key);
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
iter.remove();
}
}
}
private void getRequest(SelectionKey key) throws Exception {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer requestBuffer = ByteBuffer.allocate(1024 * 1024);
int read = client.read(requestBuffer);
requestBuffer.clear();
if(read == -1) {
key.cancel();
throw new Exception("Client disconnected at: " +
((SocketChannel) key.channel()).socket().getRemoteSocketAddress());
}
byte[] bytes = new byte[requestBuffer.limit()];
requestBuffer.get(bytes);
Message message = SerializationUtils.deserialize(bytes);
sendResponse(client, message);
}
private void sendResponse(SocketChannel client, Message message) throws IOException {
message.setResult("Some result");
ByteBuffer responseBuffer = ByteBuffer.wrap(SerializationUtils.serialize(message));
while (responseBuffer.hasRemaining()) {
client.write(responseBuffer);
}
responseBuffer.clear();
}
private void register(Selector selector, ServerSocketChannel serverSocket) throws IOException {
SocketChannel client = serverSocket.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
System.out.println("New client at: " + client.socket().getRemoteSocketAddress());
}
public static void main(String[] args) throws Exception {
new Server().start();
}
}
I try to send this object as a bytes array:
import java.io.Serializable;
import java.util.Formatter;
public class Message implements Serializable {
private String command;
private Person person;
private String result;
public Message(String command, Person person) {
this.command = command;
this.person = person;
}
public String getCommand() {
return command;
}
public void setCommand(String executedCommand) {
this.command = executedCommand;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
public String getResult() {
return result;
}
public void setResult(String result) {
this.result = result;
}
#Override
public String toString() {
return new Formatter()
.format("Command: %s\nAttached object: %s\nResult: %s",
command, person, result)
.toString();
}
}
I include instance of this class inside Message obj:
public class Person implements Serializable {
private final int state;
public Person(int state) {
this.state = state;
}
#Override
public String toString() {
return "Person state: " + state;
}
}
I have no idea what is going wrong, hope for your help.
UPD: I used 'org.apache.commons:commons-lang3:3.5' dependency to serialize an object into bytes array
I have never used Java NIO channels before, so I am not an expert. But I found out several things:
General:
In order to debug your code, it is helpful to use e.printStackTrace() instead of just System.out.println(e.getMessage()).
Client:
SocketChannel server in the client should be configured as blocking, otherwise it might read 0 bytes because there is no server response yet, which causes your problem.
You should always call ByteBuffer.clear() before reading something, not afterwards.
After reading, the position in the byte buffer has to be reset to 0 via responseBuffer.position(0) before calling get(byte[]), otherwise it will read undefined bytes after the ones just read.
You should size your byte arrays according to the number of bytes read, not the byte buffer size. It might work the other way around, but it is inefficient.
Server:
You should always call ByteBuffer.clear() before reading something, not afterwards.
After reading, the position in the byte buffer has to be reset to 0 via responseBuffer.position(0) before calling get(byte[]), otherwise it will read undefined bytes after the ones just read.
When catching exceptions during getRequest(key) calls, you should close the corresponding channel, otherwise after a client disconnects the server will indefinitely try to read from it, spamming your console log with error messages. My modification handles that case and also prints a nice log message telling which client (remote socket address) was closed.
Caveat: There is nothing in your code dealing with the situation that a request or response written into the channel on the one side is bigger than the maximum ByteBuffer size on the other side. Similarly, in theory a (de)serialised byte[] could also end up being bigger than the byte buffer.
Here are my diffs:
Index: src/main/java/de/scrum_master/stackoverflow/q65890087/Client.java
===================================================================
--- a/src/main/java/de/scrum_master/stackoverflow/q65890087/Client.java (revision Staged)
+++ b/src/main/java/de/scrum_master/stackoverflow/q65890087/Client.java (date 1612321383172)
## -15,7 +15,7 ##
public void start() throws IOException {
try {
server = SocketChannel.open(new InetSocketAddress("localhost", 5454));
- server.configureBlocking(false);
+ server.configureBlocking(true);
}
catch (IOException e) {
System.err.println("Server isn't responding");
## -56,22 +56,24 ##
getResponse();
}
catch (Exception e) {
- System.out.println(e.getMessage());
+ e.printStackTrace();
+// System.out.println(e.getMessage());
System.err.println("Connection lost");
System.exit(0);
}
}
public void getResponse() throws Exception {
- ByteBuffer responseBuffer = ByteBuffer.allocate(1024 * 1024 * 64);
+ ByteBuffer responseBuffer = ByteBuffer.allocate(1024 * 1024);
+ responseBuffer.clear();
int read = server.read(responseBuffer);
- responseBuffer.clear();
if (read == -1) {
- throw new Exception();
+ throw new Exception("EOF, cannot read server response");
}
- byte[] bytes = new byte[responseBuffer.limit()];
+ byte[] bytes = new byte[read];
+ responseBuffer.position(0);
responseBuffer.get(bytes);
Message message = SerializationUtils.deserialize(bytes);
Index: src/main/java/de/scrum_master/stackoverflow/q65890087/Server.java
===================================================================
--- a/src/main/java/de/scrum_master/stackoverflow/q65890087/Server.java (revision Staged)
+++ b/src/main/java/de/scrum_master/stackoverflow/q65890087/Server.java (date 1612323386278)
## -35,7 +35,11 ##
getRequest(key);
}
catch (Exception e) {
- System.err.println(e.getMessage());
+ e.printStackTrace();
+// System.err.println(e.getMessage());
+ SocketChannel client = (SocketChannel) key.channel();
+ System.err.println("Closing client connection at: " + client.socket().getRemoteSocketAddress());
+ client.close();
}
}
iter.remove();
## -45,15 +49,16 ##
private void getRequest(SelectionKey key) throws Exception {
SocketChannel client = (SocketChannel) key.channel();
- ByteBuffer requestBuffer = ByteBuffer.allocate(1024 * 1024 * 64);
+ ByteBuffer requestBuffer = ByteBuffer.allocate(1024 * 1024);
+ requestBuffer.clear();
int read = client.read(requestBuffer);
- requestBuffer.clear();
if (read == -1) {
key.cancel();
throw new Exception("Client disconnected at: " +
((SocketChannel) key.channel()).socket().getRemoteSocketAddress());
}
- byte[] bytes = new byte[requestBuffer.limit()];
+ byte[] bytes = new byte[read];
+ requestBuffer.position(0);
requestBuffer.get(bytes);
Message message = SerializationUtils.deserialize(bytes);
sendResponse(client, message);
Just for completeness' sake, here are the full classes after I changed them:
import org.apache.commons.lang3.SerializationUtils;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
public class Client {
private SocketChannel server;
public void start() throws IOException {
try {
server = SocketChannel.open(new InetSocketAddress("localhost", 5454));
server.configureBlocking(true);
}
catch (IOException e) {
System.err.println("Server isn't responding");
System.exit(0);
}
Scanner scRequest = new Scanner(System.in);
Scanner scState = new Scanner(System.in);
System.out.println("Enter request:");
String request = scRequest.nextLine();
while (!request.equals("exit")) {
try {
// In my actual project class Person is a way different (But it's still a POJO)
// I included it here to make sure I can get it back after sending to the server
System.out.println("Enter a number:");
Person person = new Person(scState.nextInt());
sendRequest(request, person);
System.out.println("\nEnter request:");
request = scRequest.nextLine();
}
catch (Exception e) {
e.printStackTrace();
}
}
stop();
}
public void sendRequest(String sMessage, Person person) {
Message message = new Message(sMessage, person);
ByteBuffer requestBuffer = ByteBuffer.wrap(SerializationUtils.serialize(message));
try {
server.write(requestBuffer);
requestBuffer.clear();
getResponse();
}
catch (Exception e) {
e.printStackTrace();
// System.out.println(e.getMessage());
System.err.println("Connection lost");
System.exit(0);
}
}
public void getResponse() throws Exception {
ByteBuffer responseBuffer = ByteBuffer.allocate(1024 * 1024);
responseBuffer.clear();
int read = server.read(responseBuffer);
if (read == -1) {
throw new Exception("EOF, cannot read server response");
}
byte[] bytes = new byte[read];
responseBuffer.position(0);
responseBuffer.get(bytes);
Message message = SerializationUtils.deserialize(bytes);
System.out.println(message);
}
public void stop() throws IOException {
server.close();
}
public static void main(String[] args) throws IOException {
Client client = new Client();
client.start();
}
}
import org.apache.commons.lang3.SerializationUtils;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class Server {
public void start() throws IOException {
Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open();
serverSocket.bind(new InetSocketAddress("localhost", 5454));
serverSocket.configureBlocking(false);
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server started");
while (true) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> iter = selectedKeys.iterator();
while (iter.hasNext()) {
SelectionKey key = iter.next();
if (key.isAcceptable()) {
register(selector, serverSocket);
}
if (key.isReadable()) {
try {
getRequest(key);
}
catch (Exception e) {
e.printStackTrace();
// System.err.println(e.getMessage());
SocketChannel client = (SocketChannel) key.channel();
System.err.println("Closing client connection at: " + client.socket().getRemoteSocketAddress());
client.close();
}
}
iter.remove();
}
}
}
private void getRequest(SelectionKey key) throws Exception {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer requestBuffer = ByteBuffer.allocate(1024 * 1024);
requestBuffer.clear();
int read = client.read(requestBuffer);
if (read == -1) {
key.cancel();
throw new Exception("Client disconnected at: " +
((SocketChannel) key.channel()).socket().getRemoteSocketAddress());
}
byte[] bytes = new byte[read];
requestBuffer.position(0);
requestBuffer.get(bytes);
Message message = SerializationUtils.deserialize(bytes);
sendResponse(client, message);
}
private void sendResponse(SocketChannel client, Message message) throws IOException {
message.setResult("Some result");
ByteBuffer responseBuffer = ByteBuffer.wrap(SerializationUtils.serialize(message));
while (responseBuffer.hasRemaining()) {
client.write(responseBuffer);
}
responseBuffer.clear();
}
private void register(Selector selector, ServerSocketChannel serverSocket) throws IOException {
SocketChannel client = serverSocket.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
System.out.println("New client at: " + client.socket().getRemoteSocketAddress());
}
public static void main(String[] args) throws Exception {
new Server().start();
}
}

CastException in Nio server : SocketChannelImpl cannot be cast to ServerSocketChannel

i use pseudo code to describe the problem first,and i'll paste the whole code in the follow,which can run in the local.
1.selector = Selector.open();
serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(new InetSocketAddress(port), 1024);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
2.while(true){
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
3. if(!key.isAcceptable()){
continue;
}
4. ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
...
}
}
the exception occured in the step 4,then i do a check in the step 3,but it can not pass the acceptable check and go into a dead loop.
occasionally ,it can receive and response normally and i have not make any change,it's too strange to me.
here i paste the code and hope someone can help me. thanks.
package io.Nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedSelectorException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import io.util.IOUtil;
public class NioServer extends Thread{
private int port;
private Selector selector;
private ServerSocketChannel serverChannel;
public NioServer(int port){
this.port = port;
}
#Override
public void run() {
try{
selector = Selector.open();
serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(new InetSocketAddress(port), 1024);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
}catch(IOException e){
IOUtil.close(serverChannel);
}
System.out.println("server start:" + port);
while(true){
try {
selector.select();
} catch (ClosedSelectorException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
if(!key.isValid()){
key.cancel();
IOUtil.close(key.channel());
IOUtil.close(key.selector());
System.out.println(IOUtil.now() + "clear a invalid key.");
continue;
}
// i put a check here,if is not Acceptable,then continue, but it's a dead loop
if(!key.isAcceptable()){
System.out.println("not Acceptable");
continue;
}
try {
//Exception here: SocketChannelImpl cannot be cast to ServerSocketChannel
ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
SocketChannel channel = serverChannel.accept();
if(channel == null){
continue;
}
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);
// if (key.isReadable()){
// System.out.println("not read");
// }
ByteBuffer buffer = ByteBuffer.allocate(1024);
if (channel.read(buffer) > 0) {
buffer.flip();
byte[] byteArray = new byte[buffer.remaining()];
buffer.get(byteArray);
String expression = new String(byteArray, "UTF-8");
System.out.println(IOUtil.now() + "receive request:" + expression);
String result = null;
response(channel, result);
}
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
public void shutdown(){
IOUtil.close(selector);
IOUtil.close(serverChannel);
}
private void response(SocketChannel channel, String response) throws IOException {
response = "hello response";
System.out.println(IOUtil.now() + "send response:"+ response);
byte[] bytes = response.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
buffer.put(bytes);
buffer.flip();
channel.write(buffer);
}
public static void main(String[] args) {
new NioServer(IOUtil.DEFAULT_PORT).start();
}
}
package io.Nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.concurrent.CountDownLatch;
import io.util.IOUtil;
public class NioClient extends Thread{
private volatile CountDownLatch connectLatch;
private String ip;
private int port;
private Selector selector;
private SocketChannel socketChannel;
private NioClient(String ip, int port) {
this.ip = ip;
this.port = port;
connectLatch = new CountDownLatch(1);
}
public static NioClient open(String ip, int port){
NioClient client = new NioClient(ip,port);
client.start();
return client;
}
#Override
public void run(){
try{
long begin = System.currentTimeMillis();
System.out.println(IOUtil.now() + "start client");
selector = Selector.open();
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(ip,port));
while(!socketChannel.finishConnect()){
yield();
}
System.out.println(IOUtil.now() + "cost time:" + (System.currentTimeMillis() - begin) + "ms");
connectLatch.countDown();
socketChannel.register(selector, SelectionKey.OP_CONNECT);
while(true){
selector.select();
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while(it.hasNext()){
SelectionKey key = it.next();
if(!key.isValid() || !key.isReadable()){
continue;
}
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer buffer = ByteBuffer.allocate(1024);
if(channel.read(buffer) > 0){
buffer.flip();
byte[] byteArray = new byte[buffer.remaining()];
buffer.get(byteArray);
String response = new String(byteArray,"UTF-8");
System.out.println(IOUtil.now() + "receive response:" + response);
}
}
}
}catch(IOException e){
e.printStackTrace();
}
}
public void request(String request) {
try {
connectLatch.await();
} catch (InterruptedException e) {
System.out.println(IOUtil.now() + "interrupted" + e.getMessage());
}
try {
byte[] bytes = request.getBytes();
ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
buffer.put(bytes);
buffer.flip();
socketChannel.register(selector, SelectionKey.OP_READ);
//TODO
System.out.println(IOUtil.now() + "send request:" + request);
socketChannel.write(buffer);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(final String[] args) throws InterruptedException {
NioClient client = NioClient.open(IOUtil.DEFAULT_HOST, IOUtil.DEFAULT_PORT);
client.request("hello");
// while(true){
// sleep(500);
// String request = IOUtil.buileRequest(1991);
// client.request(request);
// }
}
}
package io.util;
import java.io.Closeable;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
public class IOUtil {
public static final String DEFAULT_HOST = "127.0.0.1";
public static final int DEFAULT_PORT = 8080;
public static final String operators[] = {"+", "-", "*", "/"};
public static final int CLIENNT_NUM = 10;
public static final boolean CLIENT_CLOSEABLE = true;
public static String now(){
return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss SSS ").format(new Date());
}
public static String buileRequest(int seed){
Random random = new Random(seed);
return random.nextInt(10) + IOUtil.operators[random.nextInt(4)] + (random.nextInt(10) + 1);
}
public static void close(Closeable io) {
if (io != null) {
try {
io.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
The only way the exception you describe could occur is if you attempt that typecast on a channel which is not a ServerSocketChannel, which could happen if its key is ready but not 'acceptable'. Clearly you didn't have your step 2 when you got this exception, so you processed a 'readable' channel as though it was an 'acceptable' channel.
So the code you posted doesn't actually exhibit that problem, but it does have a large number of others. You don't need to close the selector just because a key is invalid, and if it is invalid it is already cancelled, so you don't need to cancel it, and anyway closing the channel cancels the key. Why aren't you interested in OP_READ/isReadable() on the channels you have accepted and registered for OP_READ? And why are you trying to read from a channel you have just accepted, without waiting for OP_READ?
Throw it away and have a good look at the Java NIO tutorial.
I do want to comment on one particular piece of nonsense in the client:
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(new InetSocketAddress(ip,port));
while(!socketChannel.finishConnect()){
yield();
}
Here you are performing the equivalent of a blocking-mode connect in non-blocking mode. It can all be replaced by:
socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress(ip,port));
socketChannel.configureBlocking(false);
Then:
socketChannel.register(selector, SelectionKey.OP_CONNECT);
Here you are registering for an event that has already happened. Truly bizarre. You will never get OP_CONNECT from an already-connected socket. Remove.

Server-Client chat program

I am writing a server-client chat program.
Here is my code
SERVER:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class HelloServer {
public final static int defaultPort = 2345;
public static void main(String[] args) {
int port = defaultPort;
try {
port = Integer.parseInt(args[0]);
} catch (Exception e) {
}
if (port <= 0 || port >= 65536) {
port = defaultPort;
}
try {
ServerSocket ss = new ServerSocket(port);
while (true) {
try {
Socket s = ss.accept();
String response = "Hello " + s.getInetAddress() + " on port " + s.getPort()
+ "\r\n";
response += "This is " + s.getLocalAddress() + " on port " + s.getLocalPort()
+ "\r\n";
OutputStream out = s.getOutputStream();
out.write(response.getBytes());
System.out.write(response.getBytes());
InputStream in = s.getInputStream();
System.out.println("from client");
int z = 0;
while ((z = in.read()) != -1) {
System.out.write(z);
}
} catch (IOException e) {
}
}
} catch (IOException e) {
System.err.println(e);
}
}
}
CLIENT:
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketGetINetAdd {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("192.xxx.x.xxx", 2345);
InetAddress inetAddress = socket.getInetAddress();
System.out.println("Connected to:: " + inetAddress.getHostName() + " Local address:: "
+ socket.getLocalAddress() + " Local Port:: " + socket.getLocalPort());
BufferedInputStream bfINPUT = new BufferedInputStream(socket.getInputStream());
int b = 0;
OutputStream os = System.out;
while ((b = bfINPUT.read()) != -1) {
os.write(b);
}
OutputStream osNew = socket.getOutputStream();
String s = "This Is The Client"; // data to be sent
osNew.write(s.getBytes());
os.write(s.getBytes());
}
I've connected them through my program.
But now I want to know How to send some data back to the server from client?
What would be the code for client(for sending data to server) and also the code for the server for showing the data received from the client on the console(server)?
P.S- I am a novice in network programming. Please do not criticize my coding style :P
Use server stream
OutputStream os = socket.getOutputStream();
instead of client console output stream
OutputStream os = System.out;
at client side to write back to server.
and at server side use client stream to read from client in the same manner.
InputStream in = s.getInputStream();
I have already posted a sample code on server-client communication. Read it for your learning.
You need threads. The client in this examples read the lines from the System.in and sends the line to the server. The server sends an echo.
In your real application you have to take a look of the encoding
Server
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class HelloServer {
public final static int defaultPort = 2345;
public static void main(String[] args) {
int port = defaultPort;
try {
port = Integer.parseInt(args[0]);
} catch (Exception e) {
}
if (port <= 0 || port >= 65536) {
port = defaultPort;
}
try {
ServerSocket ss = new ServerSocket(port);
while (true) {
try {
Socket s = ss.accept();
new SocketThread(s).start();
} catch (IOException e) {
}
}
} catch (IOException e) {
System.err.println(e);
}
}
public static class SocketThread extends Thread {
private Socket s;
public SocketThread(Socket s) {
this.s = s;
}
#Override
public void run() {
try {
String response = "Hello " + s.getInetAddress() + " on port "
+ s.getPort() + "\r\n";
response += "This is " + s.getLocalAddress() + " on port "
+ s.getLocalPort() + "\r\n";
OutputStream out = s.getOutputStream();
out.write(response.getBytes());
BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
while (true) {
String line = input.readLine();
System.out.println("IN: " + line);
s.getOutputStream().write(("ECHO " + line + "\n").getBytes());
s.getOutputStream().flush();
System.out.println(line);
}
} catch (IOException e) {
System.err.println(e);
}
}
}
}
Client
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class SocketGetINetAdd {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("localhost", 2345);
InetAddress inetAddress = socket.getInetAddress();
System.out.println("Connected to:: " + inetAddress.getHostName() + " Local address:: " + socket.getLocalAddress() + " Local Port:: " + socket.getLocalPort());
new OutputThread(socket.getInputStream()).start();
InputStreamReader consoleReader = new InputStreamReader(System.in);
BufferedReader in = new BufferedReader(consoleReader);
while (true) {
String inline = in.readLine();
if (inline.equals("by")) {
break;
}
inline += "\n";
socket.getOutputStream().write(inline.getBytes());
socket.getOutputStream().flush();
}
}
public static class OutputThread extends Thread {
private InputStream inputstream;
public OutputThread(InputStream inputstream) {
this.inputstream = inputstream;
}
#Override
public void run() {
BufferedReader input = new BufferedReader(new InputStreamReader(inputstream));
while (true) {
try {
String line = input.readLine();
System.out.println(line);
} catch (IOException exception) {
exception.printStackTrace();
break;
}
}
}
}
}

Stream Corrupted Exception

I'm writing a client/server program using sockets. The client first sends the file name and the server reads the file from hard disk and sends back to the client through socket. Finally the client writes the content into a file. When I run the code a java.io.StreamCorruptedException: invalid stream header error is returned.
Client code:
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ClientSocket {
private static final String SERVER_IP = "10.8.17.218";
private static final int SERVER_PORT = 5000;
String fileName;
String ip;
Socket socket;
Message msg=null,message=null;
ObjectInputStream in = null;
ObjectOutputStream out = null;
ObjectOutputStream toFile=null;
File destFile;
public ClientSocket(String ipi,String fname){
fileName = fname;
ip=ipi;
msg=new Message(fileName);
destFile=new File("C:\\DestinationDirectory",fileName);
try {
socket = new Socket(SERVER_IP, SERVER_PORT);
System.out.println("Connected to server!");
} catch (Exception ex) {
System.out.println("Error connecting to server: " + ex.getMessage());
}
while(true){
try {
if (out == null) {
out = new ObjectOutputStream(socket.getOutputStream());
}
out.writeObject(msg);
out.flush();
//get the reply from the server
if (in == null) {
in = new ObjectInputStream(socket.getInputStream());
}
message = (Message) in.readObject();
//System.out.println("Server said: " + message.getMessage());
} catch (Exception ex) {
System.out.println("Error: " + ex);
}
try {
toFile = new ObjectOutputStream(new FileOutputStream(destFile));
toFile.writeObject(message);
System.out.println(message.getMessage());
} catch (IOException ex) {
Logger.getLogger(ClientSocket.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public static void main(String[] args) {
ClientSocket cs= new ClientSocket("10.8.17.218","build.sql");
}
}
Server code:
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerFile {
private static final int PORT = 5000;
public static void main(String[] args) {
ServerSocket serverSocket = null;
Message message=null,toOut=null;
try {
//Creates a new server socket with the given port number
serverSocket = new ServerSocket(PORT);
} catch (IOException ex) {
System.out.println("Error occured while creating the server socket");
return;
}
Socket socket = null;
try {
//Waits untill a connection is made, and returns that socket
socket = serverSocket.accept();
} catch (IOException ex) {
System.out.println("Error occured while accepting the socket");
return;
}
//Now we have established the a connection with the client
System.out.println("Connection created, client IP: " + socket.getInetAddress());
ObjectInputStream in = null,fromFile=null;
ObjectOutputStream out = null,tempOut=null;
File sourceFile;
FileInputStream from=null;
BufferedInputStream bis;
String name=null;
while(true){
try {
if (in == null) {
in = new ObjectInputStream(socket.getInputStream());
}
message= (Message) in.readObject();
System.out.println("Client said: " + message.getMessage());
name=message.getMessage();
sourceFile=new File("D:\\temp\\",name);
name="D:\\temp\\"+name;
System.out.println(name);
from=new FileInputStream("D:/temp/build.sql");
bis=new BufferedInputStream(from);
fromFile=new ObjectInputStream(bis);
toOut=(Message) fromFile.readObject();
//Send a reply to the client
if (out == null) {
out = new ObjectOutputStream(socket.getOutputStream());
}
out.writeObject(toOut);
out.flush();
} catch (Exception ex) {
System.out.println("Error: " + ex);
}
}
}
}
You're creating a new ObjectInputStream per transaction in the server, yet you're using a single ObjectOutputStream in the client. You should use exactly one of each at both ends for the life of the socket.

Corrupted inputStream

It errors at the last line in the client code, with the code. java.io.StreamCorruptedException: invalid stream header: 36353137. I haven't done anything to the stream before this point, so I am unsure what could be causing the problem with the ObjectInputStream.
The server class works properly, and follows the behavior I set for it, it is only the client class that is erroring.
I thought the problem at first might be because the stream wasn't being flushed, but flushing it did not fix the issue.
Apart from that, since this error is happening so early in the code, I am at a loss as to what to add to fix it.
Client class -
import java.io.*;
import java.net.*;
public class tcpClient {
int nonce;
Socket requestSocket;
ObjectOutputStream out;
ObjectInputStream in;
String message;
tcpClient(){}
void run()
{
try{
requestSocket = new Socket("localhost", 3223);
System.out.println("Connected to localhost in port 3223");
out = new ObjectOutputStream(requestSocket.getOutputStream());
out.flush();
in = new ObjectInputStream(requestSocket.getInputStream());
Server Class -
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Calendar;
import java.util.Random;
import java.util.Scanner;
import javax.swing.Timer;
public class TCPMasterServer
implements ActionListener
{
ServerSocket server;
Socket client;
Random random;
Calendar rightNow;
Timer timer;
String ipaddress;
PrintWriter out;
BufferedReader ir;
public TCPMasterServer()
{
this.random = new Random();
this.rightNow = Calendar.getInstance();
try
{
this.server = new ServerSocket(3223);
}
catch (Exception e)
{
e.printStackTrace();
}
}
private void listenForConnection()
{
try
{
this.client = this.server.accept();
this.ipaddress = this.client.getInetAddress().getHostAddress();
System.out.println(this.rightNow.getTime() + ": Connected from: " + this.ipaddress);
this.out = new PrintWriter(this.client.getOutputStream(), true);
this.ir = new BufferedReader(new InputStreamReader(this.client.getInputStream()));
communicateWithClient();
}
catch (Exception e)
{
e.printStackTrace();
listenForConnection();
}
}
private void communicateWithClient()
{
this.timer = new Timer(2000, this);
this.timer.setRepeats(false);
this.timer.start();
try
{
int nonce = this.random.nextInt(1000000);
this.out.println(nonce);
System.out.println(this.rightNow.getTime() + ": Send nonce: " + nonce);
String input = this.ir.readLine();
Scanner in = new Scanner(input);
int nonceResponse = in.nextInt();
System.out.print(this.rightNow.getTime() + ": Received number: " + nonceResponse);
if (nonceResponse == nonce + 1)
{
System.out.println("... OK");
this.out.println("SEND_NAME");
System.out.println(this.rightNow.getTime() + ": Request name");
input = this.ir.readLine();
System.out.println(this.rightNow.getTime() + ": Received name: " + input);
this.out.println(input + " ACK");
System.out.println(this.rightNow.getTime() + ": ACK sent");
}
this.client.close();
}
catch (Exception ex)
{
System.out.println(this.rightNow.getTime() + ": Error happened. Giving up");
}
this.timer.stop();
System.out.println();
listenForConnection();
}
public void actionPerformed(ActionEvent evt)
{
try
{
System.out.println("Timer fired.");
this.client.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
public static void main(String[] args)
{
TCPMasterServer server = new TCPMasterServer();
server.listenForConnection();
}
}
You're using object streams at the server, but readers and writers at the client. That won't work. If you want to read objects you must write objects.

Categories