2017-09-20 1 views
-2

먼저 의사 코드를 사용하여 문제를 설명하고 전체 코드를 다음에서 로컬에 실행할 수 있도록 붙여 넣습니다. 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 } 
 

 
}

+0

본 적이 없습니다. 키가 유효하지 않기 때문에 선택기를 닫을 필요가 없습니다. 유효하지 않은 키이므로 이미 취소되어 있으므로 취소 할 필요가 없으며 채널을 닫으면 키가 취소됩니다. 여기 아주 이상한 코드. OP_READ에 대해 수락하고 등록한 채널에서 OP_READ에 관심이없는 이유는 무엇입니까? OP_READ를 기다리지 않고 방금 수락 한 채널에서 읽으려고하는 이유는 무엇입니까? 그리고 채널을 읽으 려 할 때 "읽지 않음"으로 인쇄하는 이유는 무엇입니까? NIO 자습서를 잘 보시길 바랍니다. 이 코드는 쓰레기입니다. – EJP

+0

잘못된 키에서'key.isReadable()'도 호출 중입니다. – EJP

+0

재생할 수 없습니다.분명히 이것은 실제 코드가 아닙니다. – EJP

답변

0

유일한 방법은 C를 설명하는 예외 ServerSocketChannel이 아닌 채널에서 해당 유형 변환을 시도하면 해당 키가 준비되었지만 '수용 가능하지 않음'일 수 있습니다. 분명히이 예외가 생겼을 때 2 단계를 거치지 않았으므로 '판독 가능'채널을 '수용 가능한'채널처럼 처리했습니다.

게시 한 코드는 실제로 그 문제를 나타내지는 않지만 다른 많은 코드가 있습니다. 키가 유효하지 않기 때문에 선택기를 닫을 필요가 없습니다. 유효하지 않은 키이므로 이미 취소되어 있으므로 취소 할 필요가 없으며 채널을 닫으면 키가 취소됩니다. OP_READ에 대해 수락하고 등록한 채널에서 OP_READ/isReadable()에 관심이없는 이유는 무엇입니까? OP_READ를 기다리지 않고 방금 수락 한 채널에서 읽으려고하는 이유는 무엇입니까?

Java NIO 자습서를 버리고 잘 살펴보십시오.

나는 클라이언트 말도 안되는 하나 개의 특정 부분에 대해 언급하고 싶어 : 여기

socketChannel = SocketChannel.open(); 
socketChannel.configureBlocking(false); 
socketChannel.connect(new InetSocketAddress(ip,port)); 
while(!socketChannel.finishConnect()){ 
    yield(); 
} 

당신은 비 블록 모드 접속이 차단 모드의 등가를 수행하고 있습니다. 그런 다음

socketChannel = SocketChannel.open(); 
socketChannel.connect(new InetSocketAddress(ip,port)); 
socketChannel.configureBlocking(false); 

: 그것은 모두 교체 할 수 있습니다 여기에

socketChannel.register(selector, SelectionKey.OP_CONNECT); 

이미을 일어난 이벤트 에 등록되어 있습니다. 정말 기괴한. 이미 연결된 소켓에서 OP_CONNECT를 얻지 못할 것입니다. 풀다.

관련 문제