java nio selector & channel usage problem - java

i am really puzzled with java nio,
package org.eclipse.java.nio.selector.test;
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.Set;
public class MySelector {
public static void main(String[] args) throws IOException {
// Create selector
Selector selector = null;
selector = Selector.open();
////////////////////////////////////////////////////////////////////////
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress(
"localhost", 4321));
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
/*
* Let's begin select
*/
while (true) {
int readyChannels = selector.select();
if (readyChannels == 0) continue;
System.out.println("Hello, selector!");
Set readyKeys = selector.selectedKeys();
Iterator it = readyKeys.iterator();
while (it.hasNext()) {
SelectionKey key = (SelectionKey )it.next();
if (key.isReadable()) {
System.out.println("It's readable!");
}
it.remove();
}
}
}
}
I want the selector to wait next input event from remote server, but it was fallen into a infinitely loop after the server reply any words, why?
i really can not understand, the 'remove' does not work?
I do not want to cancel or close the channel, i want to keep the connection, make the client wait for server's reply...

It is necessary to execute reading in the block of isReadable judge.
If you do not execute reading the data transmitted from the readable channel,
the channel is selected again. So the while loop doesn't stop.
while (it.hasNext()) {
SelectionKey key = (SelectionKey )it.next();
if (key.isReadable()) {
System.out.println("It's readable!");
// Added read operation
ByteBuffer buffer = ByteBuffer.allocate(1024);
Charset charset = Charset.forName("UTF-8");
buffer.clear();
if (socketChannel.read(buffer) < 0) {
// Client connection refused
socketChannel.close();
return;
}
buffer.flip();
System.out.println("Value = " + charset.decode(buffer).toString());
}
it.remove();
}
I think that the "remove" works. "Hello, Read selector!" might be repeatedly output.

Related

Why does this non-blocking IO call fail?

Background
I'd like to send a large (30MB, but could be much larger in the future) amount of data using Java's non-blocking SocketChannel
Why non-blocking? So that the computation of the next bytes to send isn't blocked waiting for the network
When I use the SocketChannel in blocking mode, the transfer completes without a problem
When I set the SocketChannel to non-blocking, it completes significantly faster, but the server doesn't receive all of the data
The server does receive some of the data, though
Question
Why is my large (30MB) file transfer failing when using a non-blocking Java NIO SocketChannel, and how do I fix it?
Files
I gutted the program and wrote the example so it so that it will all run in one go via javac *.java && java Main
It creates a Future for the server, a Future for the client, has the client send 30MB of random bytes to the server, and then blocks on the main thread until both Futures complete (though the server never does)
Note: This is primarily about TheClient.java
If the line between the comments <CommentOutToMakeWork> and </CommentOutToMakeWork> is commented out, the SocketChannel will be blocking and the transfer will complete
Main.java:
import java.io.IOException;
import java.lang.InterruptedException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class Main {
public static void main(String[] args) throws ExecutionException, IOException, InterruptedException {
final SocketAddress address = new InetSocketAddress("127.0.0.1", 12345);
final int size = 30 * 1000 * 1000;
ExecutorService executor = Executors.newFixedThreadPool(2);
TheServer theServer = new TheServer(address, size);
TheClient theClient = new TheClient(address, size);
Future<String> serverFuture = executor.submit(theServer);
Thread.sleep(2000);
Future<String> clientFuture = executor.submit(theClient);
System.out.println("MAIN: Received from client: " + clientFuture.get());
System.out.println("MAIN: Received from server: " + serverFuture.get());
executor.shutdown();
}
}
TheClient.java:
import java.io.IOException;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.util.Random;
import java.util.concurrent.Callable;
class TheClient implements Callable<String> {
private TheClient() {}
public TheClient(SocketAddress address, int size) {
this.size = size;
this.from = new byte[size];
this.serverAddress = address;
new Random().nextBytes(from);
}
private int size;
private byte[] from;
private SocketAddress serverAddress;
public String call() throws IOException {
SocketChannel socketChannel = SocketChannel.open();
System.out.println("CLIENT: Attempting to connect to server...");
socketChannel.connect(serverAddress);
// <CommentOutToMakeWork>
socketChannel.configureBlocking(false);
// </CommentOutToMakeWork>
System.out.println("CLIENT: Connection established. Sending " + size + " bytes.");
// For this example, this is one large write, but even my actual
// program, which uses a loop and puts smaller chunks onto the channel,
// is too fast for the SocketChannel.
socketChannel.write(ByteBuffer.wrap(from));
System.out.println("CLIENT: Write completed.");
return "CLIENT: Success!";
}
}
TheServer.java:
import java.io.IOException;
import java.io.InputStream;
import java.net.SocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.util.Random;
import java.util.concurrent.Callable;
class TheServer implements Callable<String> {
private TheServer() {}
public TheServer(SocketAddress address, int size) {
this.size = size;
this.to = new byte[size];
this.serverAddress = address;
}
private int size;
private byte[] to;
private SocketAddress serverAddress;
public String call() throws IOException {
ServerSocketChannel serverChannel = ServerSocketChannel.open().bind(serverAddress);
System.out.println("SERVER: Awaiting connection...");
InputStream clientSocketInputStream = serverChannel.accept().socket().getInputStream();
System.out.println("SERVER: Connection established. Attempting to read " + size + " bytes.");
for (int i = 0; i < size; ++i) {
to[i] = (byte) clientSocketInputStream.read();
}
System.out.println("SERVER: Read completed.");
return "SERVER: Success!";
}
}
I believe the answer lies in the WritableByteChannel.write documentation:
Unless otherwise specified, a write operation will return only after writing all of the r requested bytes. Some types of channels, depending upon their state, may write only some of the bytes or possibly none at all. A socket channel in non-blocking mode, for example, cannot write any more bytes than are free in the socket's output buffer.
So it looks like you need to use the return value of write to find out how much has been written, and handle the case when it's not all been written. What isn't clear from the description is how you handle that case - you may find you need to do some scheduling to continue writing when the socket output buffer has drained, for example.

Java nio:The client is disconnected and the server is not blocked.selector.select() always return 1

When I was learning NiO Java appeared bug. when the client disconnected, the server is not blocked.selector.select() always return 1
That‘s my code
package com.socket.Server;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
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.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class ImSocketServer {
private int port = 8888;
private Charset cs = Charset.forName("gbk");
private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);
private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
private Map<String, SocketChannel> clientsMap = new HashMap<String, SocketChannel>();
private static Selector selector;
public ImSocketServer(int port){
this.port = port;
try {
init();
} catch (Exception e) {
e.printStackTrace();
}
}
private void init() throws IOException{
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocket.bind(new InetSocketAddress(port));
selector = Selector.open();
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("server start on port:"+port);
}
private void listen(){
while (true) {
try {
System.out.println(selector.select());
Set<SelectionKey> selectionKeys = selector.selectedKeys();
for(SelectionKey key : selectionKeys){
try{
handle(key);
}
catch(Exception e){
System.out.println("挂了");
}
}
selectionKeys.clear();
selector.selectedKeys().clear();
} catch (Exception e) {
e.printStackTrace();
break;
}
}
}
private void handle(SelectionKey selectionKey) throws IOException {
ServerSocketChannel server = null;
SocketChannel client = null;
String receiveText=null;
int count=0;
if (selectionKey.isAcceptable()) {
server = (ServerSocketChannel) selectionKey.channel();
client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ);
} else if (selectionKey.isReadable()) {
client = (SocketChannel) selectionKey.channel();
rBuffer.clear();
count = client.read(rBuffer);
if (count > 0) {
rBuffer.flip();
receiveText = String.valueOf(cs.decode(rBuffer).array());
System.out.println(client.toString()+":"+receiveText);
dispatch(client, receiveText);
client = (SocketChannel) selectionKey.channel();
client.register(selector, SelectionKey.OP_READ);
}
}
}
private void dispatch(SocketChannel client,String info) throws IOException{
Socket s = client.socket();
String name = "["+s.getInetAddress().toString().substring(1)+":"+Integer.toHexString(client.hashCode())+"]";
if(!clientsMap.isEmpty()){
for(Map.Entry<String, SocketChannel> entry : clientsMap.entrySet()){
SocketChannel temp = entry.getValue();
if(!client.equals(temp)){
sBuffer.clear();
sBuffer.put((name+":"+info).getBytes());
sBuffer.flip();
temp.write(sBuffer);
}
}
}
clientsMap.put(name, client);
}
public static void main(String[] args) throws IOException {
ImSocketServer server = new ImSocketServer(7777);
server.listen();
}
}
That makes sense. The socket channel is readable all the time and the read always returns EOF.
Once you read EOF from the channel, you need to remove it from the selector.

How can I possibly avoid infinite loop in this Java server?

I am not talking about threading or anything to make this more complicated.
Most server programs I saw are like this or while(true){...} (same concept).
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.io.DataOutputStream;
import java.io.IOException;
public class TCPServer {
ServerSocket welcomeSocket;
public TCPServer(int port) throws IOException {
welcomeSocket = new ServerSocket(port);
}
public void go() throws IOException {
// This is not a valid way to wait for a socket connection, You should
// not have a forever loop or while(true)
**for (; ;) {**
Socket connectionSocket = welcomeSocket.accept();
Scanner clientIn = new Scanner(connectionSocket.getInputStream());
DataOutputStream clientOut = new DataOutputStream(connectionSocket.getOutputStream());
String clientLine = clientIn.nextLine();
String modLine = clientLine.toUpperCase();
clientOut.writeBytes(modLine + "\n");
}
}
public static void main(String[] args){
try {
TCPServer server = new TCPServer(6789);
server.go();
}
catch(IOException ioe) {
ioe.printStackTrace();
}
}
}
It is not looping permanently, your code blocks on line welcomeSocket.accept() until someone connects and only after that next lines are executed then it waits for a new connection on welcomeSocket.accept(). In other words it loops as many times as it needs( per each connection ).
If you just want to allow only one client to connect, remove for (; ;) statement. But it will require to restart your server every time.
The while(!finished) option might be a better solution than the "empty" for loop. When the exit event occurs, you just set finished to true.
You can run a scheduler with any number of thread in the pool
and prevent the main thread from termination. Here I've used input stream but you can do it in different ways. Here you can use multiple threads to get connections and customize the frequency of the scheduler.
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
import org.junit.Test;
public class MyTest {
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(4);
#Test
public void hello() {
final Runnable helloServer = new Runnable() {
public void run() {
// handle soket connection here
System.out.println("hadling connection");
}
};
final ScheduledFuture<?> helloHandle = scheduler.scheduleAtFixedRate(helloServer, 1000, 1000, TimeUnit.MILLISECONDS);
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
}

TFTP Client using Java NIO

I am trying to create a TFTP client using java NIO. I am able to receive first 512 bytes of data from server, but not able to send acknowledgement to server for getting next block of packet. I am new to java NIO and networking. Not able to find solution for it. So can anyone help me on this to find fix for it? Thanks in advance
package app.sdc.business;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import app.sdc.business.NetworkElementPool.NetworkElement;
public class TftpNioClient {
static byte OP_ERROR = 5, OP_DATAPACKET = 3, OP_ACK = 4, OP_RRQ = 1, OP_WRQ = 2;
static final String LOCALHOST = "localhost";
static InetSocketAddress server = new InetSocketAddress(LOCALHOST, 69);
// main method
public static void main(String[] args) throws IOException {
processDownload();
}
// Will start downloading of all files
public static void processDownload() throws IOException {
Selector sel = Selector.open();
for (NetworkElement ne : NetworkElementPool.getNetworkElements()) {
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(false);
channel.connect(server);
channel.register(sel, SelectionKey.OP_READ | SelectionKey.OP_WRITE, ne);
}
int counter = 0;
while (true) {
int n = sel.select(3000);
if (n < 1) {
continue;
}
Iterator<SelectionKey> itr = sel.selectedKeys().iterator();
while (itr.hasNext()) {
SelectionKey key = itr.next();
itr.remove();
if (key.isWritable()) {
counter++;
System.out.println("channel Write...");
downloadUsingTFTPProtocol(key);
} else if (key.isReadable()) {
System.out.println("Channel Read");
}
}
if (counter >= NetworkElementPool.getNetworkElements().size()) {
break;
}
}
}
// method for downloading file
private static void downloadUsingTFTPProtocol(SelectionKey keyy) throws IOException {
ByteArrayOutputStream byteOutOS = new ByteArrayOutputStream();
Selector sel = keyy.selector();
NetworkElement ne = (NetworkElement) keyy.attachment();
String fileName = ne.getFilename();
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(false);
channel.register(sel, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
boolean reqSent = false;
ByteBuffer sendBuffer = null;
ByteBuffer receivedBuffer = ByteBuffer.allocate(516);
boolean stop = false;
byte[] dataByte = null;
boolean received = false;
outer: while (true) {
int n = sel.select();
if (n < 1) {
continue;
}
Iterator<SelectionKey> itr = sel.selectedKeys().iterator();
while (itr.hasNext()) {
SelectionKey key = itr.next();
itr.remove();
DatagramChannel dc = (DatagramChannel) key.channel();
if (!received && key.isReadable()) {
System.out.println("receive packet...");
receivedBuffer.clear();
dc.receive(receivedBuffer);
stop = receivedBuffer.position() < 512;
receivedBuffer.flip();
while (receivedBuffer.hasRemaining()) {
System.out.print(receivedBuffer.get());
}
System.out.println();
dataByte = receivedBuffer.array();
received = true;
}
if (key.isWritable()) {
if (!reqSent) {
System.out.println("Sending First Request....");
sendBuffer = createInitialReadRequest("SDCSource/" + fileName);
sendBuffer.flip();
dc.send(sendBuffer, server);
reqSent = true;
} else if (received) {
System.out.println("Send Acknowledgement");
byte[] opCode = new byte[] { dataByte[0], dataByte[1] };
if (opCode[1] == OP_ERROR) {
System.out.println("Error Occured...");
break outer;
} else if (opCode[1] == OP_DATAPACKET) {
byte[] blockNumber = { dataByte[2], dataByte[3] };
sendBuffer = getAcknowledgment(blockNumber, dc, server);
sendBuffer.flip();
dc.send(sendBuffer, server);
DataOutputStream dos = new DataOutputStream(byteOutOS);
dos.write(dataByte, 4, dataByte.length - 4);
}
}
received = false;
}
if (stop) {
break outer;
}
}
}
writeFile(byteOutOS, fileName);
}
// Creates request packet to send request at the beginning
private static ByteBuffer createInitialReadRequest(final String fileName) {
String mode = "octet";
int rrqByteLength = 2 + fileName.getBytes().length + 1 + mode.getBytes().length + 1;
byte[] rrqByteArray = new byte[rrqByteLength];
ByteBuffer reqBuf = ByteBuffer.allocate(rrqByteArray.length);
reqBuf.put((byte) 0).put((byte) OP_RRQ);
reqBuf.put(fileName.getBytes());
reqBuf.put((byte) 0);
reqBuf.put(mode.getBytes());
reqBuf.put((byte) 0);
return reqBuf;
}
// Creating acknowledgement code
private static ByteBuffer getAcknowledgment(byte[] blockNumber, DatagramChannel channel, InetSocketAddress server)
throws IOException {
byte[] acknowledge = { 0, OP_ACK, blockNumber[0], blockNumber[1] };
ByteBuffer buffer = ByteBuffer.allocate(acknowledge.length);
buffer.put(acknowledge);
return buffer;
}
// Create file after all packets have been received
private static void writeFile(ByteArrayOutputStream baoStream, String fileName) {
try {
OutputStream outputStream = new FileOutputStream("SDCTarget/" + fileName);
baoStream.writeTo(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
}
}
package app.sdc.business;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
public class NetworkElementPool {
private static List<NetworkElement> networkElements;
// create a list of network elements by reading files downloading. It is just a hard-coded way to create network elements
static {
networkElements = new ArrayList<NetworkElement>();
File sourceDir = new File("C:/OpenTFTPServer/SDCSource");
if (sourceDir.exists()) {
for (String filename : sourceDir.list()) {
networkElements.add(new NetworkElement("localhost", 8080, filename));
}
} else {
System.err.println("Network Elements couldn't found...");
}
}
public static List<NetworkElement> getNetworkElements() {
return networkElements;
}
// Represents a network element
public static class NetworkElement {
private String host;
private int port;
private String filename;
public String getHost() {
return host;
}
public int getPort() {
return port;
}
public String getFilename() {
return filename;
}
public NetworkElement() {
super();
}
public NetworkElement(String host, int port, String filename) {
super();
this.host = host;
this.port = port;
this.filename = filename;
}
#Override
public String toString() {
return "NetworkElement [host=" + host + ", port=" + port + ", filename=" + filename + "]";
}
}
}
Note: TftpClient class contain one foreach loop to start downloading file from more than one network element.
You're not sending the acknowledgements at the correct time, after a read: you're sending them every time around the loop. You don't need to wait for OP_WRITE to do a write. Just write whenever you need to. You shouldn't even register for OP_WRITE most of the time. See this answer for the correct technique. But in the case of TFTP it's dubious whether you need that at all. Or NIO either.
In your code, if the key.isReadable, then you can read the packet. Then immediately followed by that you can send the ACK back to TFTP server.
} else if (received) {
This block of code can go to the line immediately next to dc.receive(receivedBuffer);
You can refer this example java nio tftp client

Selector.select() does not block

Sorry, I searched around for 2 days before I had to post this question. There are similar questions, but none of them helped me.
I am trying to create a simple chat application where the client uses (non-NIO) Socket to connect to the server that listens with a NIO ServerSocketChannel. The server uses a Selector. Until the first client connects, the Selector.select() method is blocked, as expected. But after the first client connects, Selector.select() does not block and returns immediately. This causes my while loop to run continuously.
Sorry, I've pasted the entire code so that you can copy-paste it and run it. I've just started with Java, so any help/pointers will be very much appreciated. Thank you.
P.S.: Right now, the client sends serialized object (Message object) over the socket connection and the Server reads it. Since the connection is non-blocking, the serialized object is pre-fixed with the object size (in bytes) before it is sent to the server. This allows the server to read the next "x" bytes and un-serialize into a Message object. The server code is a work in progress.
CLIENT CODE----------
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectInputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
public class ChatClient {
void go(){
User u = new User();
u.setName("UserA");
try{
u.setInet(InetAddress.getLocalHost());
}catch (UnknownHostException ex){
System.out.println(ex);
return;
}
Message m = new Message();
m.setType(3);
m.setText("This is the 1st message.");
m.setFromUser(u);
try{
Socket sock = new Socket (InetAddress.getLocalHost(), 5000);
DataOutputStream dataOut = new DataOutputStream(sock.getOutputStream());
ByteArrayOutputStream byteTemp = new ByteArrayOutputStream();
ObjectOutputStream objOut = new ObjectOutputStream (byteTemp);
objOut.writeObject(m);
objOut.flush();
objOut.close();
byte[] byteMessage = byteTemp.toByteArray();
ByteBuffer bb = ByteBuffer.allocate(4);
bb.putInt(byteMessage.length);
byte[] size = new byte[4];
size = bb.array();
System.out.println("Object size = "+byteMessage.length); //370
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
byteOut.write(size);
byteOut.write(byteMessage);
byte[] finalMessage = byteOut.toByteArray();
dataOut.write(finalMessage,0,finalMessage.length);
dataOut.flush();
System.out.println("Flushed out");
}catch (Exception ex){
System.out.println(ex);
}
}
public static void main (String args[]){
new CopyOfChatClient().go();
}
}
SERVER CODE ---------------
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
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;
import java.util.concurrent.locks.ReentrantLock;
public class CopyOfChatServer {
Object a, b;//Dummy objects for synchronization
SocketChannel clientSock=null;
Selector selector;
SelectionKey key;
void go(){
try{
a=new Object();//Dummy objects for synchronization
b=new Object();//Dummy objects for synchronization
ServerSocketChannel serverSock = ServerSocketChannel.open();
serverSock.socket().bind(new InetSocketAddress(5000));
//Note: ServerSocketChannel is blocking, but each new connection returned by accept() will be made non-blocking (see below)
selector = Selector.open();
new Thread(new SelectorThread()).start(); //Start the SelectorThread
int i=0;
while (true){
clientSock = serverSock.accept();
if (clientSock!=null){
clientSock.configureBlocking(false); //The default client socket returned by accept() is blocking. Set it to non-blocking.
synchronized (b){
selector.wakeup();
synchronized (a){
key = clientSock.register(selector, SelectionKey.OP_READ); //register new client Socket with selector
key.attach(clientSock);
}//sync(a)
}//sync(b)
i++;
}
System.out.println("Here");
}//while(true)
}catch (Exception ex){
System.out.println(ex);
}
}
class SelectorThread implements Runnable{
Set <SelectionKey> selectedKeys;
int readyChannels;
public void run(){
while (true){
try {
synchronized(a){
System.out.println("1. Selector trying to select");
readyChannels = selector.select();//Note: select() is blocking ?? Does not block. Behaves like non-blocking
System.out.println("2. Selector has selected");
}//sync a
synchronized (b){
//just wait till registration is done in main thread
}
if (readyChannels == 0) continue; //Even if select() is blocking, this check is to handle suprious wake-ups
System.out.println("readyChannels>0");
selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()){
SelectionKey key = keyIterator.next();
keyIterator.remove();//added after the first answer to my question
if (key.isReadable()){
System.out.println("3. Got incoming data");
SocketChannel tempSock = (SocketChannel)key.attachment();
ByteBuffer bb=ByteBuffer.allocate(8000);
int bytesRead=tempSock.read(bb);
System.out.println("4. Bytes read = "+bytesRead);
if (bytesRead>4){
bb.flip();
bb.rewind();
int size = bb.getInt();
System.out.println("5. Size of object = "+size);
byte[] objIn = new byte[size];
for (int i=0;i<size;i++){
objIn[i]=bb.get();
}
bb.compact();
ByteArrayInputStream bIn= new ByteArrayInputStream(objIn);
ObjectInputStream objStream= new ObjectInputStream(bIn);
Message temp1 = (Message) objStream.readObject();
System.out.println("6. Read object back");
System.out.println(temp1.getFromUser().getName());
}
}
}
selectedKeys.clear();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
public static void main (String args[]){
new CopyOfChatServer().go();
}
}
MESSAGE Class ----
import java.io.Serializable;
public class Message implements Serializable{
private int type;
private User fromUser;
private User toUser;
private String text;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public User getFromUser() {
return fromUser;
}
public void setFromUser(User fromUser) {
this.fromUser = fromUser;
}
public User getToUser() {
return toUser;
}
public void setToUser(User toUser) {
this.toUser = toUser;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
USER CLASS --------
import java.io.Serializable;
import java.net.InetAddress;
public class User implements Serializable{
private String name;
private InetAddress inet;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public InetAddress getInet() {
return inet;
}
public void setInet(InetAddress inet) {
this.inet = inet;
}
}
You must put
keyIterator.remove()
after
keyIterator.next()
The selector doesn't remove anything from selectedKeys() itself.
NB You don't need to attach the channel to the key as an attachment. You can get it from key.channel().

Categories