Reputation: 53
I'm practicing with NIO and trying to make a simple app with client and server sides. This app should just send message in bytes from clien to server and get other message as response. My code is down here. But I have a lot of different issues.
Sometimes lines int bytesRead = socketChannel.read(byteBuffer);
or bytesRead = socketChannel.read(byteBuffer);
from method readMessage()
reads endless sequence of zero bytes and throws OOM error.
Sometimes response from server looks like that instead of {"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}
.
Sometimes response has odd tail like this: {"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}YQ11ZVwA\u003d
Both server and cliend use same methods for reading and writing.
I send from client {"class":"server.PasswordHashRequest","login":"admin"}
and expect {"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}
.
With the same code I can get one issue now and other issue few minutes later.
I've tried anything I know. Did I managed to get segfault in Java?
Client side code:
@Test
public void main() throws Exception {
System.out.println("Opening socket");
InetSocketAddress socketAddress = new InetSocketAddress("localhost", 9090);
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
Selector selector = Selector.open();
socketChannel.register(selector, OP_CONNECT);
socketChannel.connect(socketAddress);
PasswordHashRequest request = new PasswordHashRequest("admin");
System.out.println("Socket open");
while (true) {
System.out.println("Client selector awoken");
selector.select();
for (SelectionKey selectionKey : selector.selectedKeys()) {
if (selectionKey.isConnectable()) {
socketChannel.finishConnect();
selectionKey.interestOps(OP_WRITE);
} else if (selectionKey.isReadable()) {
String response = ServerManager.readMessage((SocketChannel) selectionKey.channel());
System.out.println(response);
server.interrupt();
} else if (selectionKey.isWritable()) {
ServerManager.sendMessage(request, (SocketChannel) selectionKey.channel());
System.out.println("Request sent");
selectionKey.interestOps(OP_READ);
}
}
}
}
Server side code:
public void run() {
System.out.println("Main thread started");
while (true) {
try {
// Get ready channels
int readyChannels = selector.select();
if (readyChannels == 0) { continue; }
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
// Handle Events
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
// New Client
if (key.isAcceptable()) {
System.out.println("New Client Accepted");
ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
serverSocketChannel.configureBlocking(false);
SocketChannel socketChannel = serverSocketChannel.accept();
socketChannel.configureBlocking(false);
SelectionKey clientKey = socketChannel.register(selector, SelectionKey.OP_READ);
Random randomInt = new Random(System.currentTimeMillis());
clientKey.attach(randomInt.nextInt(Integer.SIZE - 1));
}
// Client has sent data
else if (key.isReadable()) {
handleInput(key);
}
keyIterator.remove();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
Read method:
public static String readMessage(SocketChannel socketChannel) throws IOException {
ByteBuffer byteBuffer = ByteBuffer.allocate(16);
byteBuffer.clear();
StringBuilder stringBuilder = new StringBuilder();
int bytesRead = socketChannel.read(byteBuffer);
while (bytesRead != -1) {
byteBuffer.flip();
String byteString = new String(byteBuffer.array(), Charset.forName("UTF-8"));
stringBuilder.append(byteString);
byteBuffer.clear();
bytesRead = socketChannel.read(byteBuffer);
}
socketChannel.shutdownInput();
return stringBuilder.toString();
}
Write method:
public static void writeMessage(String message, SocketChannel channel) throws IOException {
message += "\r\n";
System.out.println(message);
int bufferLength = 16;
byte[] responseBytes = message.getBytes();
int offset = 0;
ByteBuffer buf = ByteBuffer.allocate(bufferLength);
while (responseBytes.length > offset) {
buf.clear();
int div = responseBytes.length - offset;
if (div >= bufferLength) {
buf.put(responseBytes, offset, bufferLength);
} else {
buf.put(responseBytes, offset, div);
}
buf.flip();
channel.write(buf);
offset += bufferLength;
}
channel.shutdownOutput();
}
Upvotes: 1
Views: 836
Reputation: 310850
bytesRead <= 0
write()
returns zero, and then (and only then) register the channel for OP_WRITE, and only continue writing when it fires.See many similar questions here on all this.
Upvotes: 2