@Test @Ignore( "Very simple microbenchmark to compare different writeTo implementations. Only for development thus " + "ignored.") public void testWriteToMicrobenchmark() throws IOException { int capacity = 1024 * 128; int iterations = 100; int testRuns = 10; byte[] bytes = new byte[capacity]; ThreadLocalRandom.current().nextBytes(bytes); ByteBuffer buffer = BufferUtil.allocate(capacity); BufferUtil.append(buffer, bytes, 0, capacity); long startTest = System.nanoTime(); for (int i = 0; i < testRuns; i++) { long start = System.nanoTime(); for (int j = 0; j < iterations; j++) { ByteArrayOutputStream out = new ByteArrayOutputStream(); long startRun = System.nanoTime(); BufferUtil.writeTo(buffer.asReadOnlyBuffer(), out); long elapsedRun = System.nanoTime() - startRun; // LOG.warn("run elapsed={}ms", elapsedRun / 1000); assertThat( "Bytes in out equal bytes in buffer", Arrays.equals(bytes, out.toByteArray()), is(true)); } long elapsed = System.nanoTime() - start; LOG.warn("elapsed={}ms average={}ms", elapsed / 1000, elapsed / iterations / 1000); } LOG.warn( "overall average: {}ms", (System.nanoTime() - startTest) / testRuns / iterations / 1000); }
private void handle(SelectionKey key) throws IOException { // TODO Auto-generated method stub ServerSocketChannel server = null; SocketChannel client = null; String receiveText = null; int count = 0; if (key.isAcceptable()) { // client require accept events server = (ServerSocketChannel) key.channel(); client = server.accept(); client.configureBlocking(false); client.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { // 如果是read事件,则直接读取 client = (SocketChannel) key.channel(); recBuffer.clear(); count = client.read(recBuffer); if (count > 0) { recBuffer.flip(); receiveText = decode.decode(recBuffer.asReadOnlyBuffer()).toString(); System.out.println(client.toString() + ":" + receiveText); sendBuffer.clear(); sendBuffer.put((sdf.format(new Date()) + "服务器收到你的消息").getBytes()); sendBuffer.flip(); client.write(sendBuffer); dispatch(client, receiveText); client = (SocketChannel) key.channel(); client.register(selector, SelectionKey.OP_READ); } } }
private static void printRecords(Direction direction, ByteBuffer buf) { while (buf.hasRemaining()) { byte type = buf.get(); byte v1 = buf.get(); byte v2 = buf.get(); int len = buf.getShort(); ByteBuffer data = buf.asReadOnlyBuffer(); buf.position(buf.position() + len); data.limit(data.position() + len); System.out.println( direction + " Record type=" + type + " version=" + v1 + "." + v2 + " len=" + len); switch (type) { case CONTENTTYPE_HANDSHAKE: printHandshakeRecord(data, ((direction == Direction.IN) ? inEnc : outEnc)); break; case CONTENTTYPE_ALERT: printAlertRecord(data); break; case CONTENTTYPE_CHANGECIPHERSPEC: System.out.println(" Change Cipher Spec"); printRecordBytes(data); if (direction == Direction.OUT) outEnc = true; else inEnc = true; break; default: printRecordBytes(data); break; } } }
static void printHandshakeRecord(ByteBuffer buf, boolean enc) { while (buf.hasRemaining()) { if (enc) { System.out.println(" Handshake Encrypted"); printRecordBytes(buf); continue; } byte typeByte = buf.get(); HandshakeType type = HandshakeType.getTypeByCode(typeByte); buf.get(); short len = buf.getShort(); // uint24 ByteBuffer data = buf.asReadOnlyBuffer(); data.limit(len + data.position()); buf.position(buf.position() + len); if (type != null) { type.parse(data); } else { System.out.println(" Handshake type=" + typeByte); printRecordBytes(data); } } }
/** * Blocking send of content. * * @param content The content to send. * @throws IOException */ public void sendContent(ByteBuffer content) throws IOException { final BlockingCallback callback = _channel.getWriteBlockingCallback(); if (content.hasArray() && content.limit() < content.capacity()) content = content.asReadOnlyBuffer(); _channel.write(content, true, callback); callback.block(); }
/** * Constructs from a buffer of data and some metadata. * * @param data the binary data * @param metadata metadata, such as mime type, creation date, or the like */ public RawData(ByteBuffer data, Map<String, List<String>> metadata) { this.data = data.asReadOnlyBuffer(); Map<String, List<String>> tmpMetaData; if (metadata == null) { tmpMetaData = new HashMap<>(); } else { tmpMetaData = metadata; } this.metadata = ImmutableMap.<String, List<String>>builder().putAll(tmpMetaData).build(); }
private void testWriteToWithBufferThatDoesNotExposeArray(int capacity) throws IOException { ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] bytes = new byte[capacity]; ThreadLocalRandom.current().nextBytes(bytes); ByteBuffer buffer = BufferUtil.allocate(capacity); BufferUtil.append(buffer, bytes, 0, capacity); BufferUtil.writeTo(buffer.asReadOnlyBuffer(), out); assertThat( "Bytes in out equal bytes in buffer", Arrays.equals(bytes, out.toByteArray()), is(true)); }
@Override protected boolean afterReceived(ByteBuffer buffer) { // TODO: 以后要考虑 Header 太长导致 Host 不在第一个 buffer 里的情况 if (firstBufferReceived) { return false; } onParsedHost(HttpHeaderParser.parseHost(buffer.asReadOnlyBuffer())); firstBufferReceived = true; return false; }
public static String getString(ByteBuffer buffer) { Charset charset = null; CharsetDecoder decoder = null; CharBuffer charBuffer = null; try { charset = Charset.forName("UTF-8"); decoder = charset.newDecoder(); // charBuffer = decoder.decode(buffer);//用这个的话,只能输出来一次结果,第二次显示为空 charBuffer = decoder.decode(buffer.asReadOnlyBuffer()); return charBuffer.toString(); } catch (Exception ex) { ex.printStackTrace(); return ""; } }
/** * ************************************************************************* See description of * superclass/interface. * * @see ch.skyguide.message.structure.AbstractGenericDataBlock#encode() */ @Override public ByteBuffer encode() { ByteBuffer dataBlockBuffer = ByteBuffer.allocate(getFieldLengthIndicator()); dataBlockBuffer.put((byte) getDataCategory()); dataBlockBuffer.putShort((short) getFieldLengthIndicator()); for (GenericRecord currentRecord : m_records) { dataBlockBuffer.put(currentRecord.encode()); } dataBlockBuffer.flip(); return dataBlockBuffer.asReadOnlyBuffer(); }
/* ------------------------------------------------------------ */ @Override public ByteBuffer getDirectBuffer() { ByteBuffer buffer = _directBuffer.get(); if (buffer == null) { ByteBuffer buffer2 = ResourceCache.this.getDirectBuffer(_resource); if (buffer2 == null) LOG.warn("Could not load " + this); else if (_directBuffer.compareAndSet(null, buffer2)) { buffer = buffer2; if (!BufferUtil.isMappedBuffer(buffer) && _cachedSize.addAndGet(BufferUtil.length(buffer)) > _maxCacheSize) shrinkCache(); } else buffer = _directBuffer.get(); } if (buffer == null) return null; return buffer.asReadOnlyBuffer(); }
/** * Asynchronous send of content. * * @param content The content to send * @param callback The callback to use to notify success or failure */ public void sendContent(ByteBuffer content, final Callback callback) { if (content.hasArray() && content.limit() < content.capacity()) content = content.asReadOnlyBuffer(); _channel.write( content, true, new Callback() { @Override public void succeeded() { closed(); callback.succeeded(); } @Override public void failed(Throwable x) { callback.failed(x); } }); }
/** * {@inheritDoc} * * <p>Sends the given {@code message} to all local members of the specified channel. * * <p>TBD: (optimization) this method should handle sending multiple messages to a given * channel. */ public void send(byte[] channelId, byte[] message) { callStarted(); try { if (logger.isLoggable(Level.FINEST)) { logger.log( Level.FINEST, "send channelId:{0} message:{1}", HexDumper.toHexString(channelId), HexDumper.format(message, 0x50)); } /* * TBD: (optimization) this should enqueue the send * request and return immediately so that the * coordinator can receive the acknowledgment and * continue processing of the event queue. Right now, * process the send request inline here. */ BigInteger channelRefId = new BigInteger(1, channelId); Set<BigInteger> localMembers = localChannelMembersMap.get(channelRefId); if (localMembers == null) { // TBD: there should be local channel members. // What error should be reported here? return; } ByteBuffer msg = ByteBuffer.allocate(3 + channelId.length + message.length); msg.put(SimpleSgsProtocol.CHANNEL_MESSAGE) .putShort((short) channelId.length) .put(channelId) .put(message) .flip(); for (BigInteger sessionRefId : localMembers) { sessionService.sendProtocolMessageNonTransactional( sessionRefId, msg.asReadOnlyBuffer(), Delivery.RELIABLE); } } finally { callFinished(); } }
/** * {@inheritDoc} * * <p>Removes the channel from the per-channel cache of local member sessions, and sends a * CHANNEL_LEAVE protocol message to the channel's local member sessions. */ public void leaveAll(byte[] channelId) { callStarted(); try { if (logger.isLoggable(Level.FINEST)) { logger.log(Level.FINEST, "leaveAll channelId:{0}", HexDumper.toHexString(channelId)); } BigInteger channelRefId = new BigInteger(1, channelId); Set<BigInteger> localMembers; localMembers = localChannelMembersMap.remove(channelRefId); if (localMembers != null) { ByteBuffer msg = ByteBuffer.allocate(1 + channelId.length); msg.put(SimpleSgsProtocol.CHANNEL_LEAVE).put(channelId).flip(); for (BigInteger sessionRefId : localMembers) { sessionService.sendProtocolMessageNonTransactional( sessionRefId, msg.asReadOnlyBuffer(), Delivery.RELIABLE); } } } finally { callFinished(); } }
/** * {@inheritDoc} * * <p>Removes the specified {@code sessionId} from the per-channel cache for the given channel's * local member sessions, and sends a CHANNEL_LEAVE protocol message to the session with the * corresponding {@code sessionId}. */ public void leave(byte[] channelId, byte[] sessionId) { callStarted(); try { if (logger.isLoggable(Level.FINEST)) { logger.log( Level.FINEST, "leave channelId:{0} sessionId:{1}", HexDumper.toHexString(channelId), HexDumper.toHexString(sessionId)); } // Update local channel membership cache. BigInteger channelRefId = new BigInteger(1, channelId); Set<BigInteger> localMembers; localMembers = localChannelMembersMap.get(channelRefId); if (localMembers == null) { return; } BigInteger sessionRefId = new BigInteger(1, sessionId); localMembers.remove(sessionRefId); // Update per-session channel set cache. Set<BigInteger> channelSet = localPerSessionChannelsMap.get(sessionRefId); if (channelSet != null) { channelSet.remove(channelRefId); } // Send CHANNEL_LEAVE protocol message. ByteBuffer msg = ByteBuffer.allocate(1 + channelId.length); msg.put(SimpleSgsProtocol.CHANNEL_LEAVE).put(channelId).flip(); sessionService.sendProtocolMessageNonTransactional( sessionRefId, msg.asReadOnlyBuffer(), Delivery.RELIABLE); } finally { callFinished(); } }
/** * Core implementation updates the {@link Adler32} checksum from the data in the buffer. The * position, mark, and limit are unchanged by this operation. The operation is optimized when the * buffer is backed by an array. * * @param buf * @param pos * @param limit */ protected void update(final ByteBuffer buf, final int pos, final int limit) { assert buf != null; assert pos >= 0; assert limit > pos; // reset before computing the checksum. // chk.reset(); if (buf.hasArray()) { /* * Optimized when the buffer is backed by an array. */ final byte[] bytes = buf.array(); final int len = limit - pos; if (pos > bytes.length - len) { throw new BufferUnderflowException(); } chk.update(bytes, pos + buf.arrayOffset(), len); } else { /* * Compute the checksum of a byte[] on the native heap. * * @todo this should be a JNI call. The Adler32 class is already a * JNI implementation. */ if (a == null) { a = new byte[512]; } // isolate changes to (pos,limit). final ByteBuffer b = buf.asReadOnlyBuffer(); // stopping point. final int m = limit; // update checksum a chunk at a time. for (int p = pos; p < m; p += a.length) { // #of bytes to copy into the local byte[]. final int len = Math.min(m - p, a.length); // set the view b.limit(p + len); b.position(p); // copy into Java heap byte[], advancing b.position(). b.get(a, 0 /* off */, len); // update the running checksum. chk.update(a, 0 /* off */, len); } // This is WAY to expensive since it is a JNI call per byte. // // for (int i = pos; i < limit; i++) { // // chk.update(buf.get(i)); // // } } }
@Override public ByteBuffer asReadOnlyByteBuffer() { return buffer.asReadOnlyBuffer(); }
public ByteBuffer getDataBuffer() { return (dataBuffer != null) ? dataBuffer.asReadOnlyBuffer() : null; }
/** * {@inheritDoc} * * <p>Reads the local membership list for the specified {@code channelId}, and updates the local * membership cache for that channel. If any join or leave notifications were missed, then send * the appropriate CHANNEL_JOIN or CHANNEL_LEAVE protocol message to the effected session(s). */ public void refresh(String name, byte[] channelId) { callStarted(); if (logger.isLoggable(Level.FINE)) { logger.log(Level.FINE, "refreshing channelId:{0}", HexDumper.toHexString(channelId)); } try { BigInteger channelRefId = new BigInteger(1, channelId); GetLocalMembersTask getMembersTask = new GetLocalMembersTask(channelRefId); try { transactionScheduler.runTask(getMembersTask, taskOwner); } catch (Exception e) { // FIXME: what is the right thing to do here? logger.logThrow( Level.WARNING, e, "obtaining members of channel:{0} throws", HexDumper.toHexString(channelId)); } Set<BigInteger> newLocalMembers = Collections.synchronizedSet(getMembersTask.getLocalMembers()); if (logger.isLoggable(Level.FINEST)) { logger.log( Level.FINEST, "newLocalMembers for channel:{0}", HexDumper.toHexString(channelId)); for (BigInteger sessionRefId : newLocalMembers) { logger.log( Level.FINEST, "member:{0}", HexDumper.toHexString(sessionRefId.toByteArray())); } } /* * Determine which join and leave events were missed and * send protocol messages to clients accordingly. */ Set<BigInteger> oldLocalMembers = localChannelMembersMap.put(channelRefId, newLocalMembers); Set<BigInteger> joiners = null; Set<BigInteger> leavers = null; if (oldLocalMembers == null) { joiners = newLocalMembers; } else { for (BigInteger sessionRefId : newLocalMembers) { if (oldLocalMembers.contains(sessionRefId)) { oldLocalMembers.remove(sessionRefId); } else { if (joiners == null) { joiners = new HashSet<BigInteger>(); } joiners.add(sessionRefId); } } if (!oldLocalMembers.isEmpty()) { leavers = oldLocalMembers; } } if (joiners != null) { for (BigInteger sessionRefId : joiners) { MessageBuffer msg = new MessageBuffer(1 + MessageBuffer.getSize(name) + channelId.length); msg.putByte(SimpleSgsProtocol.CHANNEL_JOIN).putString(name).putBytes(channelId); sessionService.sendProtocolMessageNonTransactional( sessionRefId, ByteBuffer.wrap(msg.getBuffer()).asReadOnlyBuffer(), Delivery.RELIABLE); } } if (leavers != null) { for (BigInteger sessionRefId : leavers) { ByteBuffer msg = ByteBuffer.allocate(1 + channelId.length); msg.put(SimpleSgsProtocol.CHANNEL_LEAVE).put(channelId).flip(); sessionService.sendProtocolMessageNonTransactional( sessionRefId, msg.asReadOnlyBuffer(), Delivery.RELIABLE); } } } finally { callFinished(); } }
protected boolean parseContent(ByteBuffer buffer) { // Handle _content byte ch; while (_state.ordinal() < State.END.ordinal() && buffer.hasRemaining()) { switch (_state) { case EOF_CONTENT: _contentChunk = buffer.asReadOnlyBuffer(); _contentPosition += _contentChunk.remaining(); buffer.position(buffer.position() + _contentChunk.remaining()); if (_handler.content(_contentChunk)) return true; break; case CONTENT: { long remaining = _contentLength - _contentPosition; if (remaining == 0) { setState(State.END); if (_handler.messageComplete()) return true; } else { _contentChunk = buffer.asReadOnlyBuffer(); // limit content by expected size if (_contentChunk.remaining() > remaining) { // We can cast remaining to an int as we know that it is smaller than // or equal to length which is already an int. _contentChunk.limit(_contentChunk.position() + (int) remaining); } _contentPosition += _contentChunk.remaining(); buffer.position(buffer.position() + _contentChunk.remaining()); boolean handle = _handler.content(_contentChunk); if (_contentPosition == _contentLength) { setState(State.END); if (_handler.messageComplete()) return true; } if (handle) return true; } break; } case CHUNKED_CONTENT: { ch = next(buffer); if (ch > HttpTokens.SPACE) { _chunkLength = TypeUtil.convertHexDigit(ch); _chunkPosition = 0; setState(State.CHUNK_SIZE); } break; } case CHUNK_SIZE: { ch = next(buffer); if (ch == 0) break; if (ch == HttpTokens.LINE_FEED) { if (_chunkLength == 0) { setState(State.END); if (_handler.messageComplete()) return true; } else setState(State.CHUNK); } else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON) setState(State.CHUNK_PARAMS); else _chunkLength = _chunkLength * 16 + TypeUtil.convertHexDigit(ch); break; } case CHUNK_PARAMS: { ch = next(buffer); if (ch == HttpTokens.LINE_FEED) { if (_chunkLength == 0) { setState(State.END); if (_handler.messageComplete()) return true; } else setState(State.CHUNK); } break; } case CHUNK: { int remaining = _chunkLength - _chunkPosition; if (remaining == 0) { setState(State.CHUNKED_CONTENT); } else { _contentChunk = buffer.asReadOnlyBuffer(); if (_contentChunk.remaining() > remaining) _contentChunk.limit(_contentChunk.position() + remaining); remaining = _contentChunk.remaining(); _contentPosition += remaining; _chunkPosition += remaining; buffer.position(buffer.position() + remaining); if (_handler.content(_contentChunk)) return true; } break; } case CLOSED: { BufferUtil.clear(buffer); return false; } default: break; } } return false; }
public ByteBuffer getData() { return data.asReadOnlyBuffer(); }
/** * Retrieves a read-only version of this buffer. * * <p><i>Trying to manually prepare this buffer for writing is discouraged. If this buffer needs * to be written, please use {@link #getWritableBuffer()}.</i> * * @return the buffer */ public ByteBuffer getByteBuffer() { return buf.asReadOnlyBuffer(); }
@Override public void onFillable() { if (_latch != null) { try { _latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } Callback blocking = _blockingRead; if (blocking != null) { _blockingRead = null; blocking.succeeded(); return; } EndPoint _endp = getEndPoint(); try { _last = System.currentTimeMillis(); boolean progress = true; while (progress) { progress = false; // Fill the input buffer with everything available BufferUtil.compact(_in); if (BufferUtil.isFull(_in)) throw new IllegalStateException("FULL " + BufferUtil.toDetailString(_in)); int filled = _endp.fill(_in); if (filled > 0) progress = true; // If the tests wants to block, then block while (_blockAt > 0 && _endp.isOpen() && _in.remaining() < _blockAt) { FutureCallback future = _blockingRead = new FutureCallback(); fillInterested(); future.get(); filled = _endp.fill(_in); progress |= filled > 0; } // Copy to the out buffer if (BufferUtil.hasContent(_in) && BufferUtil.append(_out, _in) > 0) progress = true; // Blocking writes if (BufferUtil.hasContent(_out)) { ByteBuffer out = _out.duplicate(); BufferUtil.clear(_out); for (int i = 0; i < _writeCount; i++) { FutureCallback blockingWrite = new FutureCallback(); _endp.write(blockingWrite, out.asReadOnlyBuffer()); blockingWrite.get(); } progress = true; } // are we done? if (_endp.isInputShutdown()) _endp.shutdownOutput(); } if (_endp.isOpen()) fillInterested(); } catch (ExecutionException e) { // Timeout does not close, so echo exception then shutdown try { FutureCallback blockingWrite = new FutureCallback(); _endp.write(blockingWrite, BufferUtil.toBuffer("EE: " + BufferUtil.toString(_in))); blockingWrite.get(); _endp.shutdownOutput(); } catch (Exception e2) { // e2.printStackTrace(); } } catch (InterruptedException | EofException e) { Log.getRootLogger().ignore(e); } catch (Exception e) { Log.getRootLogger().warn(e); } finally { } }
protected boolean parseContent(ByteBuffer buffer) { int remaining = buffer.remaining(); if (remaining == 0 && _state == State.CONTENT) { long content = _contentLength - _contentPosition; if (content == 0) { setState(State.END); return _handler.messageComplete(); } } // Handle _content byte ch; while (_state.ordinal() < State.END.ordinal() && remaining > 0) { switch (_state) { case EOF_CONTENT: _contentChunk = buffer.asReadOnlyBuffer(); _contentPosition += remaining; buffer.position(buffer.position() + remaining); if (_handler.content(_contentChunk)) return true; break; case CONTENT: { long content = _contentLength - _contentPosition; if (content == 0) { setState(State.END); return _handler.messageComplete(); } else { _contentChunk = buffer.asReadOnlyBuffer(); // limit content by expected size if (remaining > content) { // We can cast remaining to an int as we know that it is // smaller than // or equal to length which is already an int. _contentChunk.limit(_contentChunk.position() + (int) content); } _contentPosition += _contentChunk.remaining(); buffer.position(buffer.position() + _contentChunk.remaining()); if (_handler.content(_contentChunk)) return true; if (_contentPosition == _contentLength) { setState(State.END); return _handler.messageComplete(); } } break; } case CHUNKED_CONTENT: { ch = next(buffer); if (ch > HttpTokens.SPACE) { _chunkLength = TypeUtils.convertHexDigit(ch); _chunkPosition = 0; setState(State.CHUNK_SIZE); } break; } case CHUNK_SIZE: { ch = next(buffer); if (ch == 0) break; if (ch == HttpTokens.LINE_FEED) { if (_chunkLength == 0) setState(State.CHUNK_END); else setState(State.CHUNK); } else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON) setState(State.CHUNK_PARAMS); else _chunkLength = _chunkLength * 16 + TypeUtils.convertHexDigit(ch); break; } case CHUNK_PARAMS: { ch = next(buffer); if (ch == HttpTokens.LINE_FEED) { if (_chunkLength == 0) setState(State.CHUNK_END); else setState(State.CHUNK); } break; } case CHUNK: { int chunk = _chunkLength - _chunkPosition; if (chunk == 0) { setState(State.CHUNKED_CONTENT); } else { _contentChunk = buffer.asReadOnlyBuffer(); if (remaining > chunk) _contentChunk.limit(_contentChunk.position() + chunk); chunk = _contentChunk.remaining(); _contentPosition += chunk; _chunkPosition += chunk; buffer.position(buffer.position() + chunk); if (_handler.content(_contentChunk)) return true; } break; } case CHUNK_END: { // TODO handle chunk trailer ch = next(buffer); if (ch == 0) break; if (ch == HttpTokens.LINE_FEED) { setState(State.END); return _handler.messageComplete(); } throw new IllegalCharacterException(_state, ch, buffer); } case CLOSED: { BufferUtils.clear(buffer); return false; } default: break; } remaining = buffer.remaining(); } return false; }