Java NIO选择器线程,按预期处理通道,但如何确保通道在使用后正确关闭?
因此,我的ServerRunnable类中有以下代码:Java NIO选择器线程,按预期处理通道,但如何确保通道在使用后正确关闭?,java,multithreading,server,nio,Java,Multithreading,Server,Nio,因此,我的ServerRunnable类中有以下代码: public class FirmwareServerRunnable implements Runnable { private static Logger log = Logger.getLogger(FirmwareServerRunnable.class .getName()); private LinkedTransferQueue<CommunicationState> co
public class FirmwareServerRunnable implements Runnable {
private static Logger log = Logger.getLogger(FirmwareServerRunnable.class
.getName());
private LinkedTransferQueue<CommunicationState> communicationQueue;
private int serverPort = 48485;
public FirmwareServerRunnable(int port,
LinkedTransferQueue<CommunicationState> communicationQueue) {
serverPort = port;
this.communicationQueue = communicationQueue;
}
private boolean running;
private ServerSocketChannel serverSocketChannel;
@Override
public void run() {
try {
Selector selector = Selector.open();
serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket serverSocket = serverSocketChannel.socket();
serverSocket.bind(new InetSocketAddress(serverPort));
log.info("Selector Thread: FirmwareServer Runnable- Listening for connections on port: "
+ serverSocket.getLocalPort());
running = true;
@SuppressWarnings("unused")
SelectionKey serverAcceptKey = serverSocketChannel.register(
selector, SelectionKey.OP_ACCEPT);
while (running) {
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
while (keyIterator.hasNext()) {
SelectionKey key = (SelectionKey) keyIterator.next();
if ((key.readyOps() & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT) {
acceptConnection(selector, key);
keyIterator.remove();
} else if ((key.readyOps() & SelectionKey.OP_READ) == SelectionKey.OP_READ) {
CommunicationState commsState = (CommunicationState) key
.attachment();
if (commsState.getCurrentState() == CommunicationState.STATE_READ) {
readFromSocketChannel(key);
keyIterator.remove();
}
} else if ((key.readyOps() & SelectionKey.OP_WRITE) == SelectionKey.OP_WRITE) {
CommunicationState commsState = (CommunicationState) key
.attachment();
if (commsState.getCurrentState() == CommunicationState.STATE_WRITE) {
writeToSocketChannel(key);
keyIterator.remove();
}
}
}
}
} catch (IOException e) {
log.error(
"Firmware Selector Thread: An IOException occurred",
e);
}
}
公共类FirmwareServerRunnable实现Runnable{
私有静态记录器log=Logger.getLogger(FirmwareServerRunnable.class
.getName());
专用链接传输队列通信队列;
专用int服务器端口=48485;
公共FirmwareServerRunnable(内部端口,
LinkedTransferQueue通信队列){
服务器端口=端口;
this.communicationQueue=通信队列;
}
私有布尔运行;
专用服务器socketchannel服务器socketchannel;
@凌驾
公开募捐{
试一试{
选择器=选择器。打开();
serverSocketChannel=serverSocketChannel.open();
serverSocketChannel.configureBlocking(false);
ServerSocket ServerSocket=serverSocketChannel.socket();
bind(新的InetSocketAddress(serverPort));
log.info(“选择器线程:固件服务器可运行-侦听端口上的连接:”
+serverSocket.getLocalPort());
运行=真;
@抑制警告(“未使用”)
SelectionKey serverAcceptKey=serverSocketChannel.register(
选择器,SelectionKey.OP_ACCEPT);
(跑步时){
selector.select();
设置selectedKeys=选择器。selectedKeys();
迭代器keyIterator=selectedKeys.Iterator();
while(keyIterator.hasNext()){
SelectionKey=(SelectionKey)keyIterator.next();
if((key.readyOps()&SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT){
接受连接(选择器、键);
keyterator.remove();
}else if((key.readyOps()&SelectionKey.OP\u READ)==SelectionKey.OP\u READ){
通讯状态通讯状态=(通讯状态)键
.附件();
if(commsState.getCurrentState()==CommunicationState.STATE\u READ){
从插座通道(键)读取;
keyterator.remove();
}
}else if((key.readyOps()&SelectionKey.OP_WRITE)==SelectionKey.OP_WRITE){
通讯状态通讯状态=(通讯状态)键
.附件();
if(commsState.getCurrentState()==CommunicationState.STATE\u WRITE){
写入socketchannel(键);
keyterator.remove();
}
}
}
}
}捕获(IOE异常){
日志错误(
“固件选择器线程:发生IOException”,
e) );
}
}
我的acceptConnection()
方法接受一个连接,并向其中添加一个CommunicationState
对象(状态机),该对象包含ByteBuffer
、当前通道状态、客户端当前在通信过程中的位置等内容。此服务器在进程中间在通信方法之间切换。最初它使用JSON消息与客户端通信,但当到达某一点时,它开始使用新固件刷新客户端 进程完成后,客户端将断开连接并重新启动。这会使我的通道处于未知状态。我不确定通道是否已关闭。 我该如何检查?我认为
selector.selectedKeys()
只返回可供操作的键是否正确?如果是这种情况,我该如何检查尚未正确关闭的连接?我可以在(运行){}循环中执行此操作吗
我一直在考虑的一个选择是将密钥本身的引用附加到CommunicationState机器上,然后我可以在进程完成后获得对通道的引用并在那里关闭它。但是出于某种原因,我对这个解决方案感到不安,我觉得它不对
如果甚至包括闭合通道密钥,我是否可以使用key.isValid()
来确认需要永久删除密钥
我很感激你对这个过程的任何想法,我一定忽略了什么
编辑:快速测试似乎表明通道关键点不包括在所选关键点集中,除非它们已准备好进行三个定义操作之一
我的测试不好。对等方关闭的连接将导致选择器将您的频道视为可读,当您从中读取时,将得到-1,此时您应关闭频道,这将取消其选择键 编辑 如果在这种情况下,即使包含闭合通道密钥,我是否可以使用key.isValid()来确认需要永久删除密钥
如果您关闭了频道,其密钥将被取消,因此下次您将无法在所选密钥集中看到它。如果对等方关闭了连接,请参见上文。好的,谢谢,my
readFromSocketChannel()
方法处理该问题。这会引发其他问题。显然,在客户端断开连接后,我在某个地方有一个循环没有正确退出。当然是这样,请重新编辑。选定的密钥集是为其注册的操作选择的密钥集。是的,我知道,我在抓救命稻草!:-)返回methodical方法就是这样。我将再次尝试一步一步地检查代码。我遇到了这样一种情况,流程正在完成,客户端成功重新启动,但我机器上的处理器保持在30%-40%之间,就好像它是cont