1.服务器与客户端注册att为NetTaskImpl
//网络连接时attach的是NetOperation子类
private void doAccept(SelectionKey key) throws IOException {
ServerContextImpl context = (ServerContextImpl) key.attachment();
NetOperation op = context.newInstance();
SocketChannel channel = ((ServerSocketChannel) key.channel()).accept();
channel.configureBlocking(false);
op.attachKey(NetModel.pollPolicy.addChannel(channel, 0, op));
}
服务器启动时serverTask与ClientTask任务,两者的子类是NetTaskImpl
public static NetTask createClientTask(int rsize, int wsize, NetProcessor processor) {
return new ClientTask(rsize, wsize, processor);
}
public static NetTask createServerTask(ServerContext context, NetProcessor processor) {
return new ServerTask((ServerContextImpl) context, processor);
}
在PollTask收到消息时doRead逻辑
Throwable catched = null;
boolean needsche = false;
if (key.isReadable()) {
try {
doRead(key);
needsche = true;
} catch (Throwable e) {
catched = e;
}
}
if (key.isWritable()) {
try {
doWrite(key);
needsche = true;
} catch (Throwable e) {
if (catched == null)
catched = e;
}
}
if (catched != null)
doClose(key, catched);
else if (needsche)
//在doRead之后会将attachement的类继续schedule
((NetOperation) key.attachment()).schedule();
NetTaskImpl中run方法
public void run() {
switch (state) {
case BINDKEY:
try {
synchronized (rbuf) {
onBindKey();
state = State.EXCHANGE;
}
total.incrementAndGet();
running.incrementAndGet();
} catch (Throwable t) {
close(t);
}
break;
case EXCHANGE:
onExchange();
if (!suspended)
enableRead();
break;
case ABORT:
state = State.CLOSED;
onAbort();
break;
case CLOSING_FLUSH:
int position = rbuf.position();
if (position > 0)
onExchange();
case CLOSING:
state = State.CLOSED;
try {
running.decrementAndGet();
onUnbindKey();
} catch (Throwable t) {
}
onClose();
default:
}
}
//如果有信息交换时交由processor处理,这里是StateTransportImpl类
void onExchange() {
try {
processor.process(recv());
} catch (Throwable e) {
close(e, State.CLOSING);
}
}
2.消息input,output处理
StateTransportImpl.process()
private volatile Codec input = NullCodec.getInstance();
private volatile Codec output = NullCodec.getInstance();
@Override
public void process(byte[] data) {
if (data.length > 0) {
if (Trace.isDebugEnabled())
Trace.debug(manager + " " + this + " process size = " + data.length);
try {
input.update(data, 0, data.length);
input.flush();
} catch (Throwable e) {
if (Trace.isInfoEnabled())
Trace.info(manager + " " + this + " process Exception : " + Helper.toHexString(data), e);
throw new RuntimeException(e);// force close
}
}
}
3.input.update中处理编码问题,limax提供了多种编码格式
//下面是输入和输出默认的编码格式,编码和解码顺序相反
@Override
public void setOutputSecurityCodec(byte[] key, boolean compress) {
if (Trace.isDebugEnabled())
Trace.debug(manager + " " + this + " setOutputSecurityCodec key = "
+ (key == null ? "" : Helper.toHexString(key)) + " compress = " + compress);
Codec codec = new BufferedSink(new NetTaskCodecSink());
if (null != key)
try {
codec = new Encrypt(codec, key);
} catch (CodecException e) {
if (Trace.isWarnEnabled())
Trace.warn("setOutputEncrypt " + this, e);
}
if (compress)
codec = new RFC2118Encode(codec);
output = codec;
}
@Override
public void setInputSecurityCodec(byte[] key, boolean compress) {
if (Trace.isDebugEnabled())
Trace.debug(manager + " " + this + " setInputSecurityCodec key = "
+ (key == null ? "" : Helper.toHexString(key)) + " compress = " + compress);
Codec codec = new CodecSink();
if (compress || null != key)
codec = new BufferedSink(codec);
if (compress)
codec = new RFC2118Decode(codec);
if (null != key)
try {
codec = new Decrypt(codec, key);
} catch (CodecException e) {
if (Trace.isWarnEnabled())
Trace.warn("setInputDecrypt " + this, e);
}
input = codec;
}
4.解密后处理消息
CoderSink.flush
@Override
public void flush() throws CodecException {
try {
if (os.remain() > 0)
dispatch(state.decode(os, StateTransportImpl.this));
} catch (Exception e) {
throw new CodecException(e);
}
}
Protocol
@Override
final void dispatch() {
((SupportDispatch) getManager()).dispatch(this, transport);
}
5.发送消息流程
Protocol.send()
public void send(Transport transport)
throws InstantiationException, SizePolicyException, CodecException, ClassCastException {
try {
final Octets data = new OctetsStream().marshal(this);
if (transport instanceof SupportStateCheck)
((SupportStateCheck) transport).check(getType(), data.size());
((SupportTypedDataTransfer) transport).send(getType(), data);
} catch (InstantiationException e) {
throw e;
} catch (SizePolicyException e) {
throw e;
} catch (CodecException e) {
throw e;
} catch (ClassCastException e) {
throw e;
} catch (Throwable e) {
throw new CodecException(e);
}
}
StateTransportImpl 发送数据
void sendData(Octets data) throws CodecException {
if (Trace.isDebugEnabled())
Trace.debug(manager + " " + this + " sendData size = " + data.size());
lock.lock();
try {
output.update(data.array(), 0, data.size());
output.flush();
} finally {
lock.unlock();
}
}
@Override
public void setOutputSecurityCodec(byte[] key, boolean compress) {
if (Trace.isDebugEnabled())
Trace.debug(manager + " " + this + " setOutputSecurityCodec key = "
+ (key == null ? "" : Helper.toHexString(key)) + " compress = " + compress);
//NetTaskCodeSink最终会在update中发送数据
Codec codec = new BufferedSink(new NetTaskCodecSink());
if (null != key)
try {
codec = new Encrypt(codec, key);
} catch (CodecException e) {
if (Trace.isWarnEnabled())
Trace.warn("setOutputEncrypt " + this, e);
}
if (compress)
codec = new RFC2118Encode(codec);
output = codec;
}
NetTaskCodecSink 发送数据
private class NetTaskCodecSink implements Codec {
@Override
public void update(byte c) throws CodecException {
update(new byte[] { c }, 0, 1);
}
@Override
public void update(byte[] data, int off, int len) throws CodecException {
if (nettask == null)
throw new CodecException("nettask has been closed.");
if (config.isCheckOutputBuffer()) {
long sendbuffersize = nettask.getSendBufferSize() + len;
long configsize = config.getOutputBufferSize();
if (sendbuffersize > configsize) {
if (Trace.isWarnEnabled())
Trace.warn(manager + " " + this + " send buffer is full! sendbuffersize " + sendbuffersize + " "
+ configsize);
close();
return;
}
}
if (Trace.isDebugEnabled())
Trace.debug(manager + " " + this + " send " + Helper.toHexString(data, off, len));
nettask.send(data, off, len);
}
@Override
public void flush() throws CodecException {
if (nettask == null)
throw new CodecException("nettask has been closed.");
}
}