我已经在PC上设置了一个mina(2.0.4)服务器,它工作正常,因为我已经在PC上编写了一个mina客户端来与它进行通信。然后我在android上实现了一个同步Mina客户端,但客户端无法解码收到的响应消息。
我是Java和android的新手,我已经花了整整3天时间。 有人请帮忙。提前谢谢。
我在这里总结了我的零件代码:
首先设置mina客户端。
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);
}
我可以将TransRequest(RegisterRequest)从android客户端发送到mina服务器,并且可以接收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)
消息heander 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源代码包含在我的包中,但没有解决。
我怀疑以下几点。
- 我可以发送Request out,它在编码时调用IoBuffer.putObject,它可以加载Request类。为什么不能加载Response类。
- 我发现Thread.currentThread()。getContextClassLoader()似乎已经过了。它是一个PathClassLoader,其libPath为null,mLibPaths只包含“/ system / lib /”,path为“。”,而不像其他类加载器,它可以加载从.apk文件中分类。有了这个ClassLoader,我认为它无法加载RegisterResponse类。这是一个线程问题吗? - 在nio处理器中运行的解码程序。
醇>