我是新的Java NIO,閱讀了一些教程後,我試圖自己寫一個簡單的NIO服務器和客戶端。 我的服務器只是做一件簡單的事情是從客戶端偵聽並打印到控制檯,客戶端只是連接到服務器併發送給它3條消息「你好」。 問題是我的服務器監聽並且與3條消息一起工作良好,之後它應該被阻塞並繼續監聽,但它不會,沒有阻塞,它在無限循環時運行它。這裏是我的服務器和客戶端:無限循環與選擇器即使沒有連接客戶端
服務器
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
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.nio.charset.CharsetDecoder;
import java.util.Iterator;
import java.util.Set;
public class Server {
public static void main(String args[]) throws Exception {
// Create the server socket channel
ServerSocketChannel server = ServerSocketChannel.open();
// nonblocking I/O
server.configureBlocking(false);
// host-port 8000
server.socket().bind(new InetSocketAddress(8000));
System.out.println("Server actives at port 8000");
// Create the selector
Selector selector = Selector.open();
// Recording server to selector (type OP_ACCEPT)
server.register(selector, SelectionKey.OP_ACCEPT);
while (selector.select() > 0) {
// Get keys
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> i = keys.iterator();
// print
System.out.println("[ " + keys.size() + " ]");
// For each keys...
while (i.hasNext()) {
SelectionKey key = (SelectionKey) i.next();
// Remove the current key
i.remove();
// if isAccetable = true
// then a client required a connection
if (key.isAcceptable()) {
// get client socket channel
SocketChannel client = server.accept();
// Non Blocking I/O
client.configureBlocking(false);
// recording to the selector (reading)
client.register(selector, SelectionKey.OP_READ);
continue;
}
// if isReadable = true
// then the server is ready to read
if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
// Read byte coming from the client
int BUFFER_SIZE = 1024;
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
try {
client.read(buffer);
} catch (Exception e) {
// client is no longer active
e.printStackTrace();
}
// Show bytes on the console
buffer.flip();
Charset charset = Charset.forName("ISO-8859-1");
CharsetDecoder decoder = charset.newDecoder();
CharBuffer charBuffer = decoder.decode(buffer);
System.out.println("[" + charBuffer.toString() + "]");
}
}
}
}
}
,這裏是我的客戶:
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 Client {
public static void main(String args[]) throws Exception {
// Create client SocketChannel
SocketChannel client = SocketChannel.open();
// nonblocking I/O
client.configureBlocking(false);
// Connection to host port 8000
client.connect(new java.net.InetSocketAddress("127.0.0.1", 8000));
// Create selector
Selector selector = Selector.open();
// Record to selector (OP_CONNECT type)
SelectionKey clientKey = client.register(selector,
SelectionKey.OP_CONNECT);
int counter = 0;
boolean chk = true;
// Waiting for the connection
while (selector.select(500) > 0 && chk) {
// Get keys
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> i = keys.iterator();
// For each key...
while (i.hasNext() && chk) {
SelectionKey key = (SelectionKey) i.next();
// Remove the current key
i.remove();
// Get the socket channel held by the key
SocketChannel channel = (SocketChannel) key.channel();
// Attempt a connection
if (key.isConnectable()) {
// Connection OK
System.out.println("Server Found");
// Close pendent connections
if (channel.isConnectionPending())
channel.finishConnect();
// Write continuously on the buffer
ByteBuffer buffer = null;
for (;chk;counter++) {
Thread.sleep(1000);
buffer = ByteBuffer.wrap(new String(" Client ").getBytes());
channel.write(buffer);
buffer.clear();
if (counter == 2)
{
chk = false;
client.close();
}
}
}
}
}
}
}
任何人都可以解釋什麼是錯我的代碼? 在此先感謝。
感謝您的回答,但我還有一個問題:爲什麼在收到3條消息之前,它被封鎖了,之後呢,它是非阻塞的? – Leo 2012-03-16 15:43:04
我回顧了你的回答「如果沒有任何東西準備好就會繼續循環」,我認爲你在這一點上是正確的,但是循環應該被'selector.select()'阻止,爲什麼它是不? – Leo 2012-03-17 02:40:26
除非您的讀取失敗,否則無法檢測到對方已斷開連接。因此,選擇將始終返回可讀的選擇鍵,相信它已準備好閱讀。現在,您有責任檢測它是否有效,並在讀取失敗時取消密鑰。改變服務器端如下,你應該沒問題。 SocketChannel client =(SocketChannel)key.channel(); int BUFFER_SIZE = 1024; ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); int bytesread = client.read(buffer); if(bytesread == -1){key.cancel(); client.close();繼續; } – Drona 2012-03-17 06:11:36