protected Object decodeBody(Channel channel, InputStream is, byte[] header) throws IOException { byte flag = header[2], proto = (byte) (flag & SERIALIZATION_MASK); Serialization s = CodecSupport.getSerialization(channel.getUrl(), proto); ObjectInput in = s.deserialize(channel.getUrl(), is); // get request id. long id = Bytes.bytes2long(header, 4); if ((flag & FLAG_REQUEST) == 0) { // decode response. Response res = new Response(id); if ((flag & FLAG_EVENT) != 0) { res.setEvent(Response.HEARTBEAT_EVENT); } // get status. byte status = header[3]; res.setStatus(status); if (status == Response.OK) { try { Object data; if (res.isHeartbeat()) { data = decodeHeartbeatData(channel, in); } else if (res.isEvent()) { data = decodeEventData(channel, in); } else { data = decodeResponseData(channel, in, getRequestData(id)); } res.setResult(data); } catch (Throwable t) { res.setStatus(Response.CLIENT_ERROR); res.setErrorMessage(StringUtils.toString(t)); } } else { res.setErrorMessage(in.readUTF()); } return res; } else { // decode request. Request req = new Request(id); req.setVersion("2.0.0"); req.setTwoWay((flag & FLAG_TWOWAY) != 0); if ((flag & FLAG_EVENT) != 0) { req.setEvent(Request.HEARTBEAT_EVENT); } try { Object data; if (req.isHeartbeat()) { data = decodeHeartbeatData(channel, in); } else if (req.isEvent()) { data = decodeEventData(channel, in); } else { data = decodeRequestData(channel, in); } req.setData(data); } catch (Throwable t) { // bad request req.setBroken(true); req.setData(t); } return req; } }
@Override public NextAction handleRead(FilterChainContext context) throws IOException { Object message = context.getMessage(); Connection<?> connection = context.getConnection(); Channel channel = GrizzlyChannel.getOrAddChannel(connection, url, handler); try { if (message instanceof Buffer) { // 收到新的数据包 Buffer buffer = (Buffer) message; // 缓存 int readable = buffer.capacity(); // 本次可读取新数据的大小 if (readable == 0) { return context.getStopAction(); } byte[] bytes; // byte[]缓存区,将Buffer转成byte[],再转成UnsafeByteArrayInputStream int offset; // 指向已用数据的偏移量,off之前的数据都是已用过的 int limit; // 有效长度,limit之后的长度是空白或无效数据,off到limit之间的数据是准备使用的有效数据 Object[] remainder = (Object[]) channel.getAttribute(BUFFER_KEY); // 上次序列化剩下的数据 channel.removeAttribute(BUFFER_KEY); if (remainder == null) { // 如果没有,创建新的bytes缓存 bytes = new byte[bufferSize]; offset = 0; limit = 0; } else { // 如果有,使用剩下的bytes缓存 bytes = (byte[]) remainder[0]; offset = (Integer) remainder[1]; limit = (Integer) remainder[2]; } return receive(context, channel, buffer, readable, bytes, offset, limit); } else if (message instanceof Object[]) { // 同一Buffer多轮Filter,即:一个Buffer里有多个请求 Object[] remainder = (Object[]) message; Buffer buffer = (Buffer) remainder[0]; int readable = (Integer) remainder[1]; byte[] bytes = (byte[]) remainder[2]; int offset = (Integer) remainder[3]; int limit = (Integer) remainder[4]; return receive(context, channel, buffer, readable, bytes, offset, limit); } else { // 其它事件直接往下传 return context.getInvokeAction(); } } finally { GrizzlyChannel.removeChannelIfDisconnectd(connection); } }
/* * 接收 * * @param context 上下文 * @param channel 通道 * @param buffer 缓存 * @param readable 缓存可读 * @param bytes 输入缓存 * @param offset 指向已读数据的偏移量,off之前的数据都是已用过的 * @param limit 有效长度,limit之后的长度是空白或无效数据,off到limit之间的数据是准备使用的数据 * @return 后续动作 * @throws IOException */ private NextAction receive( FilterChainContext context, Channel channel, Buffer buffer, int readable, byte[] bytes, int offset, int limit) throws IOException { for (; ; ) { int read = Math.min(readable, bytes.length - limit); // 取bytes缓存空闲区,和可读取新数据,的最小值,即:此次最多读写数据的大小 buffer.get(bytes, limit, read); // 从可读取新数据中,读取数据,尽量填满bytes缓存空闲区 limit += read; // 有效数据变长 readable -= read; // 可读数据变少 UnsafeByteArrayInputStream input = new UnsafeByteArrayInputStream( bytes, offset, limit - offset); // 将bytes缓存转成InputStream,不需要关闭 Object msg = upstreamCodec.decode(channel, input); // 调用Codec接口,解码数据 if (msg == Codec.NEED_MORE_INPUT) { // 如果Codec觉得数据不够,不足以解码成一个对象 if (readable == 0) { // 如果没有更多可读数据 channel.setAttribute( BUFFER_KEY, new Object[] {bytes, offset, limit}); // 放入通道属性中,等待下一个Buffer的到来 return context.getStopAction(); } else { // 扩充或挪出空闲区,并循环,直到可读数据都加载到bytes缓存 if (offset == 0) { // 如果bytes缓存全部没有被使用,如果这时数据还不够 bytes = Bytes.copyOf(bytes, bytes.length << 1); // 将bytes缓存扩大一倍 } else { // 如果bytes缓存有一段数据已被使用 int len = limit - offset; // 计算有效数据长度 System.arraycopy( bytes, offset, bytes, 0, len); // 将数据向前移到,压缩到已使用的部分,这样limit后面就会多出一些空闲,可以放数据 offset = 0; // 移到后,bytes缓存没有数据被使用 limit = len; // 移到后,有效数据都在bytes缓存最前面 } } } else { // 如果解析出一个结果 int position = input.position(); // 记录InputStream用了多少 if (position == offset) { // 如果InputStream没有被读过,就返回了数据,直接报错,否则InputStream永远读不完,会死递归 throw new IOException("Decode without read data."); } offset = position; // 记录已读数据 context.setMessage(msg); // 将消息改为解码后的对象,以便被后面的Filter使用。 if (limit - offset > 0 || readable > 0) { // 如果有效数据没有被读完,或者Buffer区还有未读数据 return context.getInvokeAction( new Object[] { buffer, readable, bytes, offset, limit }); // 正常执行完Filter,并重新发起一轮Filter,继续读 } else { // 否则所有数据读完 return context.getInvokeAction(); // 正常执行完Filter } } } }
protected void encodeRequest(Channel channel, ChannelBuffer buffer, Request req) throws IOException { Serialization serialization = getSerialization(channel); // header. byte[] header = new byte[HEADER_LENGTH]; // set magic number. Bytes.short2bytes(MAGIC, header); // set request and serialization flag. header[2] = (byte) (FLAG_REQUEST | serialization.getContentTypeId()); if (req.isTwoWay()) header[2] |= FLAG_TWOWAY; if (req.isEvent()) header[2] |= FLAG_EVENT; // set request id. Bytes.long2bytes(req.getId(), header, 4); // encode request data. int savedWriteIndex = buffer.writerIndex(); buffer.writerIndex(savedWriteIndex + HEADER_LENGTH); ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer); ObjectOutput out = serialization.serialize(channel.getUrl(), bos); try { if (req.isEvent()) { encodeEventData(channel, out, req.getData()); } else { encodeRequestData(channel, out, req.getData()); } out.flushBuffer(); } finally { // modified by lishen if (out instanceof Cleanable) { ((Cleanable) out).cleanup(); } } bos.flush(); bos.close(); int len = bos.writtenBytes(); checkPayload(channel, len); Bytes.int2bytes(len, header, 12); // write buffer.writerIndex(savedWriteIndex); buffer.writeBytes(header); // write header. buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len); }
public String telnet(Channel channel, String message) { if (message.length() > 0) { if (!extensionLoader.hasExtension(message)) { return "No such command " + message; } TelnetHandler handler = extensionLoader.getExtension(message); Help help = handler.getClass().getAnnotation(Help.class); StringBuilder buf = new StringBuilder(); buf.append("Command:\r\n "); buf.append(message + " " + help.parameter().replace("\r\n", " ").replace("\n", " ")); buf.append("\r\nSummary:\r\n "); buf.append(help.summary().replace("\r\n", " ").replace("\n", " ")); buf.append("\r\nDetail:\r\n "); buf.append(help.detail().replace("\r\n", " \r\n").replace("\n", " \n")); return buf.toString(); } else { List<List<String>> table = new ArrayList<List<String>>(); List<TelnetHandler> handlers = extensionLoader.getActivateExtension(channel.getUrl(), "telnet"); if (handlers != null && handlers.size() > 0) { for (TelnetHandler handler : handlers) { Help help = handler.getClass().getAnnotation(Help.class); List<String> row = new ArrayList<String>(); String parameter = " " + extensionLoader.getExtensionName(handler) + " " + (help != null ? help.parameter().replace("\r\n", " ").replace("\n", " ") : ""); row.add(parameter.length() > 50 ? parameter.substring(0, 50) + "..." : parameter); String summary = help != null ? help.summary().replace("\r\n", " ").replace("\n", " ") : ""; row.add(summary.length() > 50 ? summary.substring(0, 50) + "..." : summary); table.add(row); } } return "Please input \"help [command]\" show detail.\r\n" + TelnetUtils.toList(table); } }
protected void encodeResponse(Channel channel, ChannelBuffer buffer, Response res) throws IOException { try { Serialization serialization = getSerialization(channel); // header. byte[] header = new byte[HEADER_LENGTH]; // set magic number. Bytes.short2bytes(MAGIC, header); // set request and serialization flag. header[2] = serialization.getContentTypeId(); if (res.isHeartbeat()) header[2] |= FLAG_EVENT; // set response status. byte status = res.getStatus(); header[3] = status; // set request id. Bytes.long2bytes(res.getId(), header, 4); int savedWriteIndex = buffer.writerIndex(); buffer.writerIndex(savedWriteIndex + HEADER_LENGTH); ChannelBufferOutputStream bos = new ChannelBufferOutputStream(buffer); ObjectOutput out = serialization.serialize(channel.getUrl(), bos); try { // encode response data or error message. if (status == Response.OK) { if (res.isHeartbeat()) { encodeHeartbeatData(channel, out, res.getResult()); } else { encodeResponseData(channel, out, res.getResult()); } } else out.writeUTF(res.getErrorMessage()); out.flushBuffer(); } finally { // modified by lishen if (out instanceof Cleanable) { ((Cleanable) out).cleanup(); } } bos.flush(); bos.close(); int len = bos.writtenBytes(); checkPayload(channel, len); Bytes.int2bytes(len, header, 12); // write buffer.writerIndex(savedWriteIndex); buffer.writeBytes(header); // write header. buffer.writerIndex(savedWriteIndex + HEADER_LENGTH + len); } catch (Throwable t) { // 发送失败信息给Consumer,否则Consumer只能等超时了 if (!res.isEvent() && res.getStatus() != Response.BAD_RESPONSE) { try { // FIXME 在Codec中打印出错日志?在IoHanndler的caught中统一处理? logger.warn( "Fail to encode response: " + res + ", send bad_response info instead, cause: " + t.getMessage(), t); Response r = new Response(res.getId(), res.getVersion()); r.setStatus(Response.BAD_RESPONSE); r.setErrorMessage( "Failed to send response: " + res + ", cause: " + StringUtils.toString(t)); channel.send(r); return; } catch (RemotingException e) { logger.warn( "Failed to send bad_response info back: " + res + ", cause: " + e.getMessage(), e); } } // 重新抛出收到的异常 if (t instanceof IOException) { throw (IOException) t; } else if (t instanceof RuntimeException) { throw (RuntimeException) t; } else if (t instanceof Error) { throw (Error) t; } else { throw new RuntimeException(t.getMessage(), t); } } }