我 ServerRunnable 类中有以下代码:
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);
}
}
我的
acceptConnection()
方法接受一个连接并向其中添加一个CommunicationState
对象(状态机),其中包含像ByteBuffer
,当前通道状态,客户端当前所处的通信过程等信息...此服务器在过程中会在不同的通讯方式之间切换。最初它使用JSON消息与客户端通信,但当到达某一点时,它开始使用USART协议命令向客户端闪存新固件。
一旦过程完成,客户端断开连接并重新启动。这将使我的通道处于未知状态。我不确定通道是否已在我的一侧关闭。如何检查这一点?我是否正确地认为selector.selectedKeys()
只返回准备好进行操作的键?如果是这样,如何检查没有正确关闭的连接?我可以在这个ServerRunnable
while(running){}
循环中做吗?
我正在考虑的一个选项是将引用附加到CommunicationState机器本身,然后一旦过程完成,我就可以获取通道的引用并在那里关闭它。但出于某种原因,我对这个解决方案感到不安,感觉不对劲。
如果关闭的通道键也被包括在内,我可以使用key.isValid()
来确认需要永久删除该键吗?
我很感激您对此过程的任何想法,我一定忽略了某些东西。
编辑:一个快速测试似乎表明通道键不包括在所选键集中,除非它们准备好进行三个定义操作之一 我的测试有误。
readFromSocketChannel()
方法似乎没有被调用。我有记录输出读取的字节,并在通道关闭时输出日志,但两者都没有被打印出来。 - malreadFromSocketChannel()
方法。非常感谢你的耐心和帮助! - mal-1
将在byteBuffer
本身中返回,而不是在int read = socketChannel.read(byteBuffer);
返回的值中返回。 - mal