带有 Java 个 NIO 套接字的 CastException
CastException with Java NIO sockets
我一直在学习这本书 Pro Java 7 NIO.2
以更好地了解 NIO 包,并且想编写一些与网络相关的代码以更好地了解 netty 在后台的工作方式。整体错误是有道理的,但为什么会抛出错误是我无法理解的。
java.lang.ClassCastException: sun.nio.ch.ServerSocketChannelImpl cannot be cast to java.nio.channels.SocketChannel
我做的第一件事是确保我的代码 none 正在从 sun 包装中导入任何东西,并且实际上一切都使用 java.nio 包。一切似乎都结账了。
当我尝试将客户端连接到服务器时抛出此错误,但真正困扰我的是一般事实,即它正在尝试类型转换为 ServerSocketChannel 并且不仅仅是一个 SocketChannel,这让我相信服务器很困惑。
对于下面的代码墙,我深表歉意,但由于每个人总是要求我 post 一个 运行 示例,所以我打算这样做。这是三个 class 小文件。
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)
我可能应该补充一点,selectionkey.channel() 中的类型转换 socketchannel 的实现直接来自 JavaDocs -- http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2
sun.nio.ch.* 类 似乎包含 java.nio.* 包中的一些接口实现;到不同包的交叉发生在您正在使用的实现 类 中。没什么大不了的。
通过查看 sun.nio.ch.ServerSocketChannelImpl 的源代码,我发现它实现了 java.nio.channels.ServerSocketChannel,而不是 java.nio.channels.SocketChannel。它是通道实现,而不是套接字实现。 ServerSocketChannel 和 SocketChannel(在 java.nio.channels 中)都扩展了 AbstractSelectableChannel,但它们在继承层次结构中是兄弟,而不是 ancestor/descendant.
希望对您有所帮助。
您将错误的 SelectionKey
传递给了 new Connection(...)
。您正在传递服务器套接字的密钥。您应该传递的密钥是接受的套接字密钥,它是下一行 socketChannel.register()
的结果。
我一直在学习这本书 Pro Java 7 NIO.2
以更好地了解 NIO 包,并且想编写一些与网络相关的代码以更好地了解 netty 在后台的工作方式。整体错误是有道理的,但为什么会抛出错误是我无法理解的。
java.lang.ClassCastException: sun.nio.ch.ServerSocketChannelImpl cannot be cast to java.nio.channels.SocketChannel
我做的第一件事是确保我的代码 none 正在从 sun 包装中导入任何东西,并且实际上一切都使用 java.nio 包。一切似乎都结账了。
当我尝试将客户端连接到服务器时抛出此错误,但真正困扰我的是一般事实,即它正在尝试类型转换为 ServerSocketChannel 并且不仅仅是一个 SocketChannel,这让我相信服务器很困惑。
对于下面的代码墙,我深表歉意,但由于每个人总是要求我 post 一个 运行 示例,所以我打算这样做。这是三个 class 小文件。
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)
我可能应该补充一点,selectionkey.channel() 中的类型转换 socketchannel 的实现直接来自 JavaDocs -- http://www.onjava.com/pub/a/onjava/2002/09/04/nio.html?page=2
sun.nio.ch.* 类 似乎包含 java.nio.* 包中的一些接口实现;到不同包的交叉发生在您正在使用的实现 类 中。没什么大不了的。
通过查看 sun.nio.ch.ServerSocketChannelImpl 的源代码,我发现它实现了 java.nio.channels.ServerSocketChannel,而不是 java.nio.channels.SocketChannel。它是通道实现,而不是套接字实现。 ServerSocketChannel 和 SocketChannel(在 java.nio.channels 中)都扩展了 AbstractSelectableChannel,但它们在继承层次结构中是兄弟,而不是 ancestor/descendant.
希望对您有所帮助。
您将错误的 SelectionKey
传递给了 new Connection(...)
。您正在传递服务器套接字的密钥。您应该传递的密钥是接受的套接字密钥,它是下一行 socketChannel.register()
的结果。