1

私は PC に mina(2.0.4) サーバーをセットアップしました。それと通信するために PC に mina クライアントを作成したので、問題なく動作します。次に、Androidに同期Minaクライアントを実装しましたが、クライアントは受信した応答メッセージをデコードできません。

私はJavaとAndroidが初めてで、丸3日間努力しました。誰でも助けてください。よろしくお願いします。

ここに私の部品コードを要約しました:

最初にミナクライアントをセットアップします。

public boolean startMinaClient(){
    MessageCodecFactory factory  = new MessageCodecFactory();
    factory.addMessageDecoder(ResponseDecoder.class);
    factory.addMessageEncoder(TransRequest.class, RequestEncoder.class);
    connector = new NioSocketConnector();
    connector.setConnectTimeoutMillis(30000L);
    connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(factory));

    SocketSessionConfig cfg = (SocketSessionConfig) connector.getSessionConfig();
    cfg.setUseReadOperation(true);
    ConnectFuture future = connector.connect(new InetSocketAddress(server, Config.MINA_SERVER_PORT));
    future.awaitUninterruptibly();
    session = future.getSession();
}

次に、メッセージ機能を送信します。

public synchronized MessageBase send(MessageBase message) throws MinaException {

    TransRequest request = new TransRequest(); //TransRequest is a wrapper class, with the to be sent message embedded inside.
    request.setMessage(message);  //This message can be RegisterRequest.
    WriteFuture future = session.write(request);  //write to server.
    future.awaitUninterruptibly();    //wait server reply.
    if(future.getException() != null){
        throw new MinaException(future.getException().getMessage()); //
    }
    ReadFuture readFuture = session.read();  //server replied, and the client try to read the response.
    readFuture.awaitUninterruptibly();
    if(readFuture.getException() != null) {
        throw new MinaException(readFuture.getException().getMessage());
    }
    TransResponse response = (TransResponse) readFuture.getMessage(); //read operation, need to call decoder.
    if(response == null){
        throw new MinaException("No response from MINA server.");
    }
    return response.getMessage();
}

そして私のデコーダクラス。

//base class of DecoderBase
public abstract class DecoderBase<T extends MessageBase> extends CodecBase implements MessageDecoder {

    private static CharsetDecoder decoder = CodecBase.getCharset().newDecoder();
    private Class<T> messageType;
    private T decodingMessage;

    protected CharsetDecoder getCharsetDecoder() {
            return decoder;
    }

    public GeoDecoderBase() {
            messageType = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public MessageDecoderResult decodable(IoSession session, IoBuffer in) {
            try {
                    decodingMessage = messageType.newInstance();
                    Log.d(TAG, "Decoding messate type: " + messageType.getName()
                                    + ", content: " + decodingMessage.toString());
            } catch (InstantiationException e) {
                    return MessageDecoderResult.NOT_OK;
            } catch (IllegalAccessException e) {
                    return MessageDecoderResult.NOT_OK;
    }

            if (in.remaining() < 8/* message header length */) {
                    return MessageDecoderResult.NEED_DATA;        //data not receive complete.
            }

            int messageCode = in.getInt();
            if (messageCode != decodingMessage.getMessageCode()) {
                    return MessageDecoderResult.NOT_OK;          //ensure receive the right message.
            }

            int messageLen = in.getInt();
            if (in.remaining() < messageLen) {
                    return MessageDecoderResult.NEED_DATA;
            }

            return MessageDecoderResult.OK;
    }

    //start to decode message from iobuffer.
public MessageDecoderResult decode(IoSession session, IoBuffer in,
        ProtocolDecoderOutput out) throws Exception {

    // First decode message header.
    int messageCode = in.getInt();
    decodingMessage.setMessageCode(messageCode);    //decodingMessage is the message instance.
    int messageLen = in.getInt();   

    int start = in.position();

    DecodeMessageBody(in, decodingMessage);       //decode the embedded message inside TransResponse.

    int actlen = in.position() - start;
    if (actlen != messageLen) {
        Log.e(TAG, Config.ERROR_STRING + messageType.getName() + " decodes error length. actlen=" + actlen);
        return MessageDecoderResult.NOT_OK;
    }

    out.write(decodingMessage);
    return MessageDecoderResult.OK;
}

protected abstract void DecodeMessageBody(IoBuffer in, final T message)
        throws Exception;
}

応答メッセージ デコーダ。

public class ResponseDecoder extends DecoderBase<TransResponse> {

    private String TAG = "ResponseDecoder";

    @Override
    protected void DecodeMessageBody(IoBuffer in, TransResponse message)
            throws Exception {
            int messageCode = in.getInt();
            message.setCode(messageCode);

            MessageBase base = null;
            switch(messageCode){
            case MessageCode.REGISTER_RESPONSE:
                    base = (MessageBase) in.getObject();
                    break;
            default:
                    Log.e(TAG, Config.ERROR_STRING + "unknown Message Code:0x%x" + messageCode);
                    break;
            }
            message.setMessage(base);
    }

Android クライアントから mina サーバーに TransRequest(RegisterRequest) を送信し、TransResponse(RegisterResponse) を受信できます。しかし、クライアントは常にそれをデコードできません。エラーは次のとおりです。

java.lang.ClassNotFoundException: com.geoxy.message.user.RegisterResponse 
(Hexdump: 12 00 00 2A 00 00 00 D4 12 04 00 02 00 00 00 CC AC ED 00 05 73 72 01 00 27 63 6F 6D 2E 67 
65 6F 78 79 2E 6D 65 73 73 61 67 65 2E 75 73 65 72 2E 52 65 67 69 73 74 65 72 52 65 73 70 6F 6E 73 
65 78 72 01 00 1D 63 6F 6D 2E 67 65 6F 78 79 2E 63 6F 6D 6D 6F 6E 2E 52 65 73 70 6F 6E 73 65 42 61 
73 65 78 72 01 00 1C 63 6F 6D 2E 67 65 6F 78 79 2E 63 6F 6D 6D 6F 6E 2E 4D 65 73 73 61 67 65 42 61 
73 65 78 70 12 04 00 02 73 72 01 00 2D 63 6F 6D 2E 67 65 6F 78 79 2E 63 6F 6D 6D 6F 6E 2E 4D 65 73 
73 61 67 65 42 61 73 65 24 4D 65 73 73 61 67 65 53 69 67 6E 61 74 75 72 65 78 70 00 00 00 00 00 00 
00 07 00 00 00 00 00 00 00 00 71 00 7E 00 03 00 70 00 00 00 00 00 00 00 07)

メッセージ ヘッダー 12 00 00 2A 00 00 00 D4 12 04 00 02 00 00 00 CC は正しいです (2 メッセージ コード/長さのペア)。

私のメッセージクラス。

public abstract class MessageBase implements Serializable {
    private static final long serialVersionUID = -6083872909378830262L;
    private MessageSignature signatures = new MessageSignature();
    private int messageCode;

    public MessageBase(){}  //c-tor

    //inner class.
    private class MessageSignature implements Serializable {
            private static final long serialVersionUID = -4028675440079310028L;
            long  para;

        public MessageSignature(){} //c-tor
    }
}

public abstract class ResponseBase extends MessageBase {
    private static final long serialVersionUID = -1007022532151329442L;
    protected byte result;
    protected String indication = null;    

    public ResponseBase(){} //c-tor
}
public class RegisterResponse extends ResponseBase {
    private long userId;

    public RegisterResponse() {} //c-tor
}

mina のソースコードをデバッグしました。例外コード行は IoBuffer:getObject() メソッドにあります。

IoBuffer:getObject() 

@Override
public Object getObject(final ClassLoader classLoader)  
        throws ClassNotFoundException {
**//classLoader is passed Thread.currentThread().getContextClassLoader()**
    if (!prefixedDataAvailable(4)) {
        throw new BufferUnderflowException();
    }

    int length = getInt();
    if (length <= 4) {
        throw new BufferDataException(
                "Object length should be greater than 4: " + length);
    }

    int oldLimit = limit();
    limit(position() + length);
    try {
        ObjectInputStream in = new ObjectInputStream(asInputStream()) {
            @Override
            protected ObjectStreamClass readClassDescriptor()
                    throws IOException, ClassNotFoundException {
                int type = read();
                if (type < 0) {
                    throw new EOFException();
                }
                switch (type) {
                case 0: // NON-Serializable class or Primitive types
                    return super.readClassDescriptor();
                case 1: // Serializable class
                    String className = readUTF();   //**className is correct. "com.....RegisterResponse"**
                    Class<?> clazz = Class.forName(className, true,
                            classLoader);           //**run to exception.**
                    return ObjectStreamClass.lookup(clazz);   
                default:
                    throw new StreamCorruptedException(
                            "Unexpected class descriptor type: " + type);
                }
            }

            @Override
            protected Class<?> resolveClass(ObjectStreamClass desc)
                    throws IOException, ClassNotFoundException {
                String name = desc.getName();
                try {
                    return Class.forName(name, false, classLoader);  
                } catch (ClassNotFoundException ex) {
                    return super.resolveClass(desc);
                }
            }
        };
        return in.readObject();
    } catch (IOException e) {
        throw new BufferDataException(e);
    } finally {
        limit(oldLimit);
    }
}

例外コード行: readClassDescriptor() 関数。

Class<?> clazz = Class.forName(className, true,
                        classLoader);           //**run to exception.**

サーバー側のコードと同じパッケージ名で、すべての要求/応答クラスを既に配置しています。送受信は AsyncTask で実行されます。mina のソース コードをパッケージに含めようとしましたが、解決しませんでした。

以下の点を疑いました。

  1. エンコード時に IoBuffer.putObject を呼び出す Request を送信できます。これにより、Request クラスをロードできます。Response クラスを読み込めません。
  2. Thread.currentThread().getContextClassLoader() がおかしいようです。libPath が null である PathClassLoader であり、mLibPaths には「/system/lib/」のみが含まれ、パスは「.」であり、.apk ファイルからクラス化してロードできる他のクラス ローダーとは異なります。この ClassLoader では、RegisterResponse クラスをロードできないと思います。それはスレッドの問題ですか? -- nio プロセッサで実行されるデコード手順。
4

0 に答える 0