먼저 의사 코드를 사용하여 문제를 설명하고 전체 코드를 다음에서 로컬에 실행할 수 있도록 붙여 넣습니다. Nio 서버의 CastException : SocketChannelImpl을 ServerSocketChannel에 캐스팅 할 수 없습니다.
1.selector = Selector.open();
serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(false);
serverChannel.socket().bind(new InetSocketAddress(port), 1024);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
2.while(true){
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
3. if(!key.isAcceptable()){
continue;
}
4. ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
...
}
}
예외
는 그때 3 단계에서 검사를 수행하는 단계 (4)에서 발생하지만, 허용 검사를 통과하고 죽은 루프에 들어갈 수 없다. 경우에 따라 정상적으로 응답하고 응답 할 수 있으며 변경하지 않았기 때문에 나에게 너무 이상합니다. 여기 코드를 붙여 누군가 나를 도울 수 있기를 바랍니다. 감사.package io.Nio;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedSelectorException;
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 io.util.IOUtil;
public class NioServer extends Thread{
\t private int port;
\t private Selector selector;
\t private ServerSocketChannel serverChannel;
\t public NioServer(int port){
\t \t this.port = port;
\t }
\t @Override
\t public void run() {
\t \t try{
\t \t \t selector = Selector.open();
\t \t \t serverChannel = ServerSocketChannel.open();
\t \t \t serverChannel.configureBlocking(false);
\t \t \t serverChannel.socket().bind(new InetSocketAddress(port), 1024);
\t \t \t serverChannel.register(selector, SelectionKey.OP_ACCEPT);
\t \t }catch(IOException e){
\t \t \t IOUtil.close(serverChannel);
\t \t }
\t \t System.out.println("server start:" + port);
\t \t while(true){
\t \t \t try {
\t \t \t \t selector.select();
\t \t \t } catch (ClosedSelectorException e) {
\t \t \t \t e.printStackTrace();
\t \t \t }catch (IOException e) {
\t \t \t \t e.printStackTrace();
\t \t \t }
\t \t \t Set<SelectionKey> keys = selector.selectedKeys();
\t \t \t Iterator<SelectionKey> it = keys.iterator();
\t \t \t while (it.hasNext()) {
\t \t \t \t SelectionKey key = it.next();
\t \t \t \t if(!key.isValid()){
\t \t \t \t \t key.cancel();
\t \t \t \t \t IOUtil.close(key.channel());
\t \t \t \t \t IOUtil.close(key.selector());
\t \t \t \t \t System.out.println(IOUtil.now() + "clear a invalid key.");
\t \t \t \t \t continue;
\t \t \t \t }
\t \t \t \t
\t \t \t \t // i put a check here,if is not Acceptable,then continue, but it's a dead loop
\t \t \t \t if(!key.isAcceptable()){
\t \t \t \t \t System.out.println("not Acceptable");
\t \t \t \t \t continue;
\t \t \t \t }
\t \t \t \t try {
\t \t \t \t \t //Exception here: SocketChannelImpl cannot be cast to ServerSocketChannel
\t \t \t \t \t ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
\t \t \t \t \t SocketChannel channel = serverChannel.accept();
\t \t \t \t \t if(channel == null){
\t \t \t \t \t \t continue;
\t \t \t \t \t }
\t \t \t \t \t channel.configureBlocking(false);
\t \t \t \t \t channel.register(selector, SelectionKey.OP_READ);
\t \t \t \t \t
// \t \t \t \t \t if (key.isReadable()){
// \t \t \t \t \t \t System.out.println("not read");
// \t \t \t \t \t }
\t \t \t \t \t ByteBuffer buffer = ByteBuffer.allocate(1024);
\t \t \t \t \t if (channel.read(buffer) > 0) {
\t \t \t \t \t \t buffer.flip();
\t \t \t \t \t \t byte[] byteArray = new byte[buffer.remaining()];
\t \t \t \t \t \t buffer.get(byteArray);
\t \t \t \t \t \t String expression = new String(byteArray, "UTF-8");
\t \t \t \t \t \t System.out.println(IOUtil.now() + "receive request:" + expression);
\t \t \t \t \t \t String result = null;
\t \t \t \t \t \t response(channel, result);
\t \t \t \t \t }
\t \t \t \t }catch (IOException e) {
\t \t \t \t \t e.printStackTrace();
\t \t \t \t }
\t \t \t }
\t \t }
\t }
\t public void shutdown(){
\t \t IOUtil.close(selector);
\t \t IOUtil.close(serverChannel);
\t }
\t private void response(SocketChannel channel, String response) throws IOException {
\t \t response = "hello response";
\t \t System.out.println(IOUtil.now() + "send response:"+ response);
\t \t byte[] bytes = response.getBytes();
\t \t ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
\t \t buffer.put(bytes);
\t \t buffer.flip();
\t \t channel.write(buffer);
\t }
\t public static void main(String[] args) {
\t \t new NioServer(IOUtil.DEFAULT_PORT).start();
\t }
}
package io.Nio;
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.concurrent.CountDownLatch;
import io.util.IOUtil;
public class NioClient extends Thread{
\t private volatile CountDownLatch connectLatch;
\t private String ip;
\t private int port;
\t private Selector selector;
\t private SocketChannel socketChannel;
\t private NioClient(String ip, int port) {
\t \t this.ip = ip;
\t \t this.port = port;
\t \t connectLatch = new CountDownLatch(1);
\t }
\t public static NioClient open(String ip, int port){
\t \t NioClient client = new NioClient(ip,port);
\t \t client.start();
\t \t return client;
\t }
\t @Override
\t public void run(){
\t \t try{
\t \t \t long begin = System.currentTimeMillis();
\t \t \t System.out.println(IOUtil.now() + "start client");
\t \t \t selector = Selector.open();
\t \t \t socketChannel = SocketChannel.open();
\t \t \t socketChannel.configureBlocking(false);
\t \t \t socketChannel.connect(new InetSocketAddress(ip,port));
\t \t \t while(!socketChannel.finishConnect()){
\t \t \t \t yield();
\t \t \t }
\t \t \t System.out.println(IOUtil.now() + "cost time:" + (System.currentTimeMillis() - begin) + "ms");
\t \t \t connectLatch.countDown();
\t \t \t socketChannel.register(selector, SelectionKey.OP_CONNECT);
\t \t \t while(true){
\t \t \t \t selector.select();
\t \t \t \t Iterator<SelectionKey> it = selector.selectedKeys().iterator();
\t \t \t \t while(it.hasNext()){
\t \t \t \t \t SelectionKey key = it.next();
\t \t \t \t \t if(!key.isValid() || !key.isReadable()){
\t \t \t \t \t \t continue;
\t \t \t \t \t }
\t \t \t \t \t SocketChannel channel = (SocketChannel) key.channel();
\t \t \t \t \t ByteBuffer buffer = ByteBuffer.allocate(1024);
\t \t \t \t \t if(channel.read(buffer) > 0){
\t \t \t \t \t \t buffer.flip();
\t \t \t \t \t \t byte[] byteArray = new byte[buffer.remaining()];
\t \t \t \t \t \t buffer.get(byteArray);
\t \t \t \t \t \t String response = new String(byteArray,"UTF-8");
\t \t \t \t \t \t System.out.println(IOUtil.now() + "receive response:" + response);
\t \t \t \t \t }
\t \t \t \t }
\t \t \t }
\t \t }catch(IOException e){
\t \t \t e.printStackTrace();
\t \t }
\t }
\t
\t public void request(String request) {
\t \t try {
\t \t \t connectLatch.await();
\t \t } catch (InterruptedException e) {
\t \t \t System.out.println(IOUtil.now() + "interrupted" + e.getMessage());
\t \t }
\t \t try {
\t \t \t byte[] bytes = request.getBytes();
\t \t \t ByteBuffer buffer = ByteBuffer.allocate(bytes.length);
\t \t \t buffer.put(bytes);
\t \t \t buffer.flip();
\t \t \t socketChannel.register(selector, SelectionKey.OP_READ);
\t \t \t //TODO
\t \t \t System.out.println(IOUtil.now() + "send request:" + request);
\t \t \t socketChannel.write(buffer);
\t \t } catch (IOException e) {
\t \t \t e.printStackTrace();
\t \t }
\t }
\t public static void main(final String[] args) throws InterruptedException {
\t \t NioClient client = NioClient.open(IOUtil.DEFAULT_HOST, IOUtil.DEFAULT_PORT);
\t \t client.request("hello");
// \t \t while(true){
// \t \t \t sleep(500);
// \t \t \t String request = IOUtil.buileRequest(1991);
// \t \t \t client.request(request);
// \t \t }
\t }
}
package io.util;
import java.io.Closeable;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
public class IOUtil {
\t public static final String DEFAULT_HOST = "127.0.0.1";
\t public static final int DEFAULT_PORT = 8080;
\t public static final String operators[] = {"+", "-", "*", "/"};
\t public static final int CLIENNT_NUM = 10;
\t public static final boolean CLIENT_CLOSEABLE = true;
\t
\t public static String now(){
\t \t return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss SSS ").format(new Date());
\t }
\t
\t public static String buileRequest(int seed){
\t \t Random random = new Random(seed);
\t \t return random.nextInt(10) + IOUtil.operators[random.nextInt(4)] + (random.nextInt(10) + 1);
\t }
\t public static void close(Closeable io) {
\t \t if (io != null) {
\t \t \t try {
\t \t \t \t io.close();
\t \t \t } catch (IOException e) {
\t \t \t \t e.printStackTrace();
\t \t \t }
\t \t }
\t }
}
본 적이 없습니다. 키가 유효하지 않기 때문에 선택기를 닫을 필요가 없습니다. 유효하지 않은 키이므로 이미 취소되어 있으므로 취소 할 필요가 없으며 채널을 닫으면 키가 취소됩니다. 여기 아주 이상한 코드. OP_READ에 대해 수락하고 등록한 채널에서 OP_READ에 관심이없는 이유는 무엇입니까? OP_READ를 기다리지 않고 방금 수락 한 채널에서 읽으려고하는 이유는 무엇입니까? 그리고 채널을 읽으 려 할 때 "읽지 않음"으로 인쇄하는 이유는 무엇입니까? NIO 자습서를 잘 보시길 바랍니다. 이 코드는 쓰레기입니다. – EJP
잘못된 키에서'key.isReadable()'도 호출 중입니다. – EJP
재생할 수 없습니다.분명히 이것은 실제 코드가 아닙니다. – EJP