我一直在研究这本书Pro Java 7 NIO.2
,以便更好地了解NIO包,并希望研究一些与网络相关的代码,以便更好地理解netty在后台的工作原理。总体错误是有道理的,但错误被抛出的原因超出了我的理解范围。
java.lang.ClassCastException: sun.nio.ch.ServerSocketChannelImpl cannot be cast to java.nio.channels.SocketChannel
我做的第一件事就是确保我的代码都没有从sun包装中导入任何东西,并且事实上所有东西都是使用java.nio包。似乎一切都结束了。
我尝试将客户端连接到服务器时会抛出此错误,但实际上困扰我的一般事实是它尝试输入到ServerSocketChannel而不是只是一个SocketChannel,这让我相信服务器很困惑。
我事先为下面的代码墙道歉,但是因为每个人总是要求我发布一个正在运行的例子,我打算这样做。这是三个小类文件。
TcpProcessor.java
package net.ogserver.proto.tcp;
import java.io.IOException;
import java.net.InetSocketAddress;
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 net.ogserver.proto.connections.Connection;
public class TcpProcessor implements Runnable {
public static int tcpPort;
public void run() {
try (Selector selector = Selector.open();
ServerSocketChannel serverSocket = ServerSocketChannel.open()) {
if((serverSocket.isOpen()) && (selector.isOpen())) {
serverSocket.configureBlocking(false);
serverSocket.bind(new InetSocketAddress(tcpPort));
serverSocket.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Server has started and is waiting for connections...");
while(!Thread.interrupted()) {
selector.select();
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while(keys.hasNext()) {
SelectionKey key = (SelectionKey) keys.next();
keys.remove();
if(!key.isValid()) {
continue;
}
if(key.isAcceptable()) {
processIncomingConnection(key, selector);
} else if(key.isReadable()) {
//processIncomingData(key);
} else if(key.isWritable()) {
//pushOutgoingData(key);
}
}
}
} else {
System.err.println("There was an issue constructing the socket.");
}
} catch(IOException e) {
e.printStackTrace();
}
}
private void processIncomingConnection(SelectionKey selectionKey, Selector selector) throws IOException {
ServerSocketChannel serverSocket = (ServerSocketChannel)selectionKey.channel();
SocketChannel clientSocket = serverSocket.accept();
clientSocket.configureBlocking(false);
System.out.println("Incoming connection from " + clientSocket.getRemoteAddress());
selectionKey.attach(new Connection(selectionKey));
clientSocket.register(selector, SelectionKey.OP_READ);
}
}
Connection.java
package net.ogserver.proto.connections;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
public class Connection {
private SelectionKey selectionKey;
private SocketChannel clientSocket;
private ByteBuffer networkInputBuffer;
private ByteBuffer networkOutputBuffer;
public Connection(SelectionKey selectionKey) {
this.selectionKey = selectionKey;
this.clientSocket = (SocketChannel)selectionKey.channel();
this.networkInputBuffer = ByteBuffer.allocate(1024);
this.networkOutputBuffer = ByteBuffer.allocate(8192);
}
public SelectionKey getSelectionKey() {
return selectionKey;
}
public ByteBuffer getInputBuffer() {
return networkInputBuffer;
}
public ByteBuffer getOutputBuffer() {
return networkOutputBuffer;
}
public SocketChannel getChannel() {
return clientSocket;
}
}
Server.java
package net.ogserver.proto;
import net.ogserver.proto.tcp.TcpProcessor;
public class Server {
private Thread tcpProcessor;
public Server(int port) {
TcpProcessor.tcpPort = port;
tcpProcessor = new Thread(new TcpProcessor());
tcpProcessor.start();
}
public static void main(String[] args) {
new Server(5055);
}
}
调用TcpProcessor#processIncomingConnection
时会发生错误,该错误会调用新Connection
实例的创建。抛出这个错误的那一行是本书的直接引用,我已经看过其他一些NIO服务器,并且大部分内容都是完全相同的(减去一些命名)。
this.clientSocket = (SocketChannel)selectionKey.channel();
非常感谢任何帮助,为需要它的人提供完整的控制台输出:
Server has started and is waiting for connections...
Incoming connection from /127.0.0.1:53221
Exception in thread "Thread-0" java.lang.ClassCastException: sun.nio.ch.ServerSocketChannelImpl cannot be cast to java.nio.channels.SocketChannel
at net.ogserver.proto.connections.Connection.<init>(Connection.java:17)
at net.ogserver.proto.tcp.TcpProcessor.processIncomingConnection(TcpProcessor.java:60)
at net.ogserver.proto.tcp.TcpProcessor.run(TcpProcessor.java:37)
at java.lang.Thread.run(Thread.java:745)
我应该补充说,类型化socketconnel的实现形成了selectionkey.channel()直接来自JavaDocs - http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2
答案 0 :(得分:1)
您将错误的SelectionKey
传递给new Connection(...)
。您正在传递服务器套接字密钥。你应该传递的密钥是下一行接受的套接字密钥,它是socketChannel.register()
的结果。
答案 1 :(得分:-2)
sun.nio.ch。*类似乎包含java.nio。*包中的一些接口实现;不同包的交叉发生在您正在使用的实现类中。那里没什么大不了的。
通过查看sun.nio.ch.ServerSocketChannelImpl的源代码,我发现它实现了java.nio.channels.ServerSocketChannel,而不是java.nio.channels.SocketChannel。它是一个通道实现,而不是套接字实现。 ServerSocketChannel和SocketChannel(在java.nio.channels中)都扩展了AbstractSelectableChannel,但它们是继承层次结构中的兄弟,而不是祖先/后代。
希望有所帮助。