我的意图是客户端先向服务端发送数据,然后服务端向客户端发送数据,完成一次数据交换。但是客户端第一次访问的时候是可以的,第二次访问时服务端不能获取数据了?这个问题困扰我两天了,刚学NIO 完全不明白为什么?
环境:jdk 1.8,win 10.
另外客户端是不是一般都不这么写?是不是直接用socket比较好?
客户端用Socket试了一下发现第二次访问服务端还是不能接受到数据...
服务端代码:
package cs;
import java.net.InetSocketAddress;
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.Iterator;
import java.util.Set;
public class Server {
public static void main(String[] args) throws Exception {
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);
ssc.socket().bind(new InetSocketAddress(8888));
Selector selector = Selector.open();
ssc.register(selector, SelectionKey.OP_ACCEPT);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (true) {
int readyNum = selector.select();
if (readyNum == 0) {
System.out.println("------------------");
continue;
}
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
if (key.isAcceptable()) {
// 接受连接
SocketChannel accept = ((ServerSocketChannel) key.channel()).accept();
accept.configureBlocking(false);
accept.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// 通道可读
SocketChannel clientChannel = (SocketChannel) key.channel();
System.out.println("有可读通道...");
while (clientChannel.read(buffer) > 0) {
buffer.flip();
byte[] bytes = new byte[buffer.limit()];
buffer.get(bytes);
System.out.println(new String(bytes));
buffer.clear();
}
//这里如果条件改成等-1的话第二次访问会空循环
if (clientChannel.read(buffer) <= 0) {
key.interestOps(SelectionKey.OP_WRITE);
}
} else if (key.isWritable()) {
// 通道可写
System.out.println("写");
SocketChannel channel = (SocketChannel) key.channel();
buffer.clear();
buffer.put("OVER".getBytes());
buffer.flip();
channel.write(buffer);
channel.close();
}
}
}
}
}
客户端代码:
package cs;
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.Scanner;
@SuppressWarnings("all")
public class Client {
public static void main(String[] args) throws Exception {
SocketChannel channel = SocketChannel.open(new InetSocketAddress(8888));
channel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_WRITE);
while (true) {
int numReady = selector.select();
if (numReady == 0) {
continue;
}
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
if (key.isWritable()) {
System.out.println("可写");
SocketChannel channel1 = (SocketChannel) key.channel();
buffer.put("测试文本".getBytes());
buffer.flip();
channel1.write(buffer);
buffer.clear();
channel.shutdownOutput();
key.interestOps(SelectionKey.OP_READ);
} else if (key.isReadable()) {
System.out.println("可读");
buffer.clear();
SocketChannel readChannel = (SocketChannel) key.channel();
//客户端每次能收到数据
while (readChannel.read(buffer) > 0) {
buffer.flip();
byte[] bytes = new byte[buffer.limit()];
buffer.get(bytes);
System.out.println(new String(bytes));
buffer.clear();
}
if (readChannel.read(buffer) == -1) {
readChannel.close();
return;
}
}
}
System.out.println("===");
}
}
}
服务端
key.isAcceptable()
分支,每次读数据前需要清空缓冲:buffer.clear();
中间混合各种奇奇怪怪的问题让我忽略了这一点。。。