package com.leetcode.random.difficulty;
import org.junit.Test;
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.*;
public class Design {
public static void main(String args[]) throws IOException {
System.out.println("开始输入");
Scanner scan = new Scanner(System.in);
SocketChannel channel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888));
channel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (scan.hasNext()) {
String str = scan.next();
buffer.put((new Date().toString()+"——>"+str).getBytes());
buffer.flip();
channel.write(buffer);
buffer.clear();
}
System.out.println("jieshu");
}
@Test
public void serverdemo() throws IOException {
ServerSocketChannel channel = ServerSocketChannel.open();
channel.socket().bind(new InetSocketAddress(8888));
channel.configureBlocking(false);
ByteBuffer b = ByteBuffer.allocate(10);
Selector s = Selector.open();
channel.register(s,SelectionKey.OP_ACCEPT);
while (s.select() > 0) {
Set<SelectionKey> se = s.selectedKeys();
for (SelectionKey next: se) {
se.remove(next);
if (next.isAcceptable()) {
SocketChannel sc = channel.accept();
sc.configureBlocking(false);
sc.register(s, SelectionKey.OP_READ);
}
if (next.isReadable()) {
SocketChannel sc = (SocketChannel) next.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int length = 0;
while ((length = sc.read(byteBuffer))>0) {
byteBuffer.flip();
System.out.println(new String(byteBuffer.array(), 0, length));
byteBuffer.clear();
}
}
}
}
}
}
代码功能:main方法不断通过控制台输入请求socket连接,发送信息;服务端打印信息。
服务端代码注意:
Set<SelectionKey>必须把遍历过的对象remove,否则下次再拿到用过的key,得到的SocketChannel sc = channel.accept()是null。因此在Selector中注册事件激活以后,如果不手动移除key,他会一直存在。
学习的时候有这么一句话:“SocketChannel可以重用,但socket不能重用!”
我想这句话的意思是:在Seletor中就是指“选择键Key”不能重复使用,用完要移除,否则下次遍历再拿到旧Key,但里面已经没有Socket连接了(给取走过.getChannel),因此再调用getChannel返回null。此时会报java.lang.NullPointerException: Cannot invoke "java.nio.channels.SocketChannel.configureBlocking(boolean)" because "sc" is null