Пожалуйста, поделитесь своими идеями о том, как мы можем решить это исключение
Мы работаем над Netconf Over SSH, и используемая библиотека SSH — это Apache Mina и SSHD. Устройство — это сервер Netconf, а приложение — клиент Netconf. Поскольку устройство находится за брандмауэром, приложение не может подключиться к устройству, но устройство может подключиться к приложению. Итак, мы используем сеанс, установленный устройством для приложения, для всей связи.
Ниже приведены шаги:
NioSocketAcceptor начал прослушивание/привязку к номеру порта
Для атрибута useReadoperation ioSessionConfig задано значение true
Когда tcp-соединение принято, у нас есть доступный IoSession mina core, здесь мы называем его tcpSession.
Мы хотели использовать этот мина IoSession для чтения и записи сообщений netconf. Код, используемый для преобразования основного сеанса mina в ssdh IOSession, выглядит следующим образом
новый org.apache.sshd.common.io.IoSession() {
@Override public long getId() { return tcpSession.getId(); } @Override public Object getAttribute(final Object key) { return tcpSession.getAttribute(key); } @Override public Object setAttribute(final Object key, final Object value) { return tcpSession.getAttribute(key, value); } @Override public SocketAddress getRemoteAddress() { return tcpSession.getRemoteAddress(); } @Override public SocketAddress getLocalAddress() { return tcpSession.getLocalAddress(); } @Override public IoWriteFuture write(final Buffer buffer) { final ChannelAsyncOutputStream.IoWriteFutureImpl ioWriteFuture = new ChannelAsyncOutputStream.IoWriteFutureImpl(buffer); byte[] bytes = buffer.getCompactData(); int capacity = bytes.length + 8; IoBuffer bytebuffer = IoBuffer.allocate(capacity).setAutoExpand(true); //bytebuffer.putInt(bytes.length); bytebuffer.put(bytes); bytebuffer.flip(); buffer.clear(); final WriteFuture write = tcpSession.write(bytebuffer); write.addListener(new IoFutureListener<WriteFuture>() { @Override public void operationComplete(final WriteFuture future) { if (future.isWritten()) { ioWriteFuture.setValue(true); } else { // TODO check the value type expected + if exception can go there ioWriteFuture.setValue(future.getException()); } } }); return ioWriteFuture; } @Override public CloseFuture close(final boolean immediately) { final DefaultCloseFuture defaultCloseFuture = new DefaultCloseFuture(null); tcpSession.close(immediately).addListener(new IoFutureListener<org.apache.mina.core.future.CloseFuture>() { @Override public void operationComplete(final org.apache.mina.core.future.CloseFuture future) { if(future.isClosed()) { defaultCloseFuture.setValue(true); } else { // TODO check the value type expected defaultCloseFuture.setValue(false); } } }); return defaultCloseFuture; } @Override public IoService getService() { throw new UnsupportedOperationException("No service available"); } @Override public boolean isClosed() { return tcpSession.getCloseFuture().isClosed(); } @Override public boolean isClosing() { return tcpSession.isClosing(); } });
Код, используемый для подключения Apache SSHD IoSession к клиенту, приведен ниже.
окончательный ConnectFuture connectFuture = новый DefaultConnectFuture (ноль); Сеанс ClientSessionImpl = null; попробуйте { сеанс = новый ClientSessionImpl (sshClient, ioSession); AbstractSession.attachSession (ioSession, сеанс); MyAsyncSshHandlerReader async = новый MyAsyncSshHandlerReader (ioSession); } catch (Exception e) { // TODO Автоматически сгенерированный блок catch e.printStackTrace(); }
MyAsyncSshHandlerReader — это класс, используемый для чтения данных из tcpSession.
класс MyAsyncSshHandlerReader реализует IoFutureListener, AutoCloseable {
private final org.apache.sshd.common.io.IoSession ioSession; public MyAsyncSshHandlerReader(org.apache.sshd.common.io.IoSession ioSession) { this.ioSession = ioSession; minaCoreIoSession.read().addListener(this); } @Override public void close() throws Exception { // TODO Auto-generated method stub } @Override public void operationComplete(ReadFuture future) { long msgsRead = future.getSession().getReadMessages(); if(future.isRead() && !future.isClosed()){ IoBuffer msg = (IoBuffer)future.getMessage(); msg.flip(); Buffer buf = new Buffer(msg.array()); try { if(AbstractSession.getSession(ioSession) != null){ AbstractSession.getSession(ioSession).messageReceived(buf); } } catch (Exception e) { e.printStackTrace(); } minaCoreIoSession.read().addListener(this); } }
}
Когда сеанс клиента создается на стороне приложения, вызываются следующие методы.
- sendIdentification
- пожалуйста, проясните, как работает метод AbstractSession.decode()
Приложение также получило идентификационное сообщение и обмен ключами с устройства, и идентификационное сообщение читается правильно, но не может декодировать сообщение об обмене ключами, библиотека выдала SshException недопустимая длина пакета 0
Из моей отладки переменные rpos и limit содержат одно и то же значение, например, 1536. То, как я читаю, имеет какую-то проблему?
- Изучив множество примеров и библиотеку Apache mina, я обнаружил, что проблема заключается в том, как мы читаем из ядра IoSession mina.
отправитьKexInit()