NIO has three core parts: Buffer, Channel, and Selector. In this article, WE will introduce the Http11InputBuffer Buffer.

Nio common methods

  • A byte bufferByteBufferContains several basic properties:
    • Position: current subscript position, indicating the start position for the next read/write operation
    • Limit: indicates the (maximum) end position for the next read/write operation
    • Capacity: indicates the capacity of the ByteBuffer
    • Mark: custom mark position. Default is -1
    • Mark <= position <= limit <= capacity
  • ByteBuffertheallocate()The limit and capacity values are equal to the allocated length. The limit and capacity values are equal to the allocated length
  • put()Method writes bytes, at which point position shifts the length of bytes
  • get()Method reads bytes with position marked +1
  • rewind()Method, position is changed to 0
  • flip()Method, change limit to position and position to 0
  • compact()Position =limit-position, limit= Capacity
  • mark()Method to set mark to the current position
  • clear()Set position to 0, mark to -1, and limit to Capacity
  • reset()Method, set position to the current mark, not -1
  • SocketChanneltheread()The ByteBuffer () method reads data into the specified buffer, starts with position, and returns the number of bytes nRead read. Position =position+nRead This method is non-blocking.
  • Can be achieved bynew String(byteBuffer.array(),"UTF-8")Quickly view the data in byteBuffer
  • Can be achieved bynew String(byteBuffer.array(),0,byteBuffer.limit())Quickly view the data in byteBuffer
  • CharBufferCharacter buffering, which is much the same as byte buffering

The creation of Http11Processor

The task thread pool, named http-NiO-8080-exec-xxx by default, places threads wrapped by SocketProcessorBase, and the pointcut begins with its run() method.

SocketProcessorBase->run(): // SocketProcessorBase is an abstract class that subclasses the SocketProcessor of NioEndpoint; // SocketProcessorBase calls the doRun() method of the subclass doRun(); NioEndpoint->SocketProcessor->doRun(): state = getHandler().process(socketWrapper, event); AbstractProtocol->ConnectionHandler->process(): // The processor is the processing class. // The processor is first obtained from the cache. If the cache is not available, the corresponding processing class...... is created based on the protocol // Http11Processor has two important member variables, inputBuffer and outputBuffer. Http11InputBuffer state = processor.process(wrapper, status); AbstractProcessorLight->process(): state = service(socketWrapper);Copy the code

Http11InputBuffer

Http11InputBuffer Built-in ByteBuffer, which is used to read socket key

Http11Processor->service(): // If byteBuffer is empty or its capacity is smaller than bufLength, Distribution bufLength length number of bytes / / bufLength. By default for AbstractHttp11Protocol maxHttpHeaderSize + SocketProperties. AppReadBufSize, Inputbuffer. init(socketWrapper) is settable; . // Parse the request line if (! inputBuffer.parseRequestLine(keptAlive, protocol.getConnectionTimeout(), protocol.getKeepAliveTimeout())) { if (inputBuffer.getParsingRequestLinePhase() == -1) { return SocketState.UPGRADING; } else if (handleIncompleteRequestLineRead()) { break; }}... // The omitted part parses the request headers, in much the same way that the request rows are parsed. It validates some of the attributes in the request header in the HEADERS attribute, continuing with the assignment of Request prepareRequest(); . getAdapter().service(request, response); .Copy the code

Http11InputBuffer built-in org. Apache. Coyote. Request, it has to do with Http11Processor built-in request is an object, the parsing process to request assignment, the request here is the original request

Http11InputBuffer->parseRequestLine(): if (! parsingRequestLine) { return true; } if (parsingRequestLinePhase < 2) {parsingRequestLinePhase < 2; If (bytebuffer.position () >= bytebuffer.limit ()) {if (! fill(false)) { // --1 parsingRequestLinePhase = 1; return false; If (parsingRequestLinePhase == 2) {...... // Read from 0 to the first space and set the method property (POST) if (parsingRequestLinePhase == 2) {...... If (parsingRequestLinePhase == 3) {...... if (parsingRequestLinePhase == 3) {...... // Read Spaces or tabs, if there is a question mark, If (parsingRequestLinePhase == 4) {set queryString (name=123&password=123456); . If (parsingRequestLinePhase == 5) {...... if (parsingRequestLinePhase == 5) {...... // Reading the next line break, set the protocol property (here HTTP/1.1) if (parsingRequestLinePhase == 6) {...... ParsingRequestLine = false; parsingRequestLine = false; parsingRequestLinePhase = 0; parsingRequestLineEol = false; parsingRequestLineStart = 0; return true; Nio uses channel.read and returns 0 if no data is read Http11InputBuffer->fill(): // --1 bytebuffer.mark (); Read int nRead = wrapper.read(block, ByteBuffer); Bytebuffer.limit (bytebuffer.position ()).reset(); if (nRead > 0) { return true; } else if (nRead == -1) {throw new EOFException(sm.getString(" ib.eof.error")); } else { return false; }Copy the code

In each step of the parsing process, there will be a judgment of insufficient data. Fill method will be used to try to read the data. If the data cannot be read, it will directly return to end the processing. When Poller detects a readable event for the channel again, NIO reads the data from the channel again and continues processing where it last left off. And so on, the channel is finally read.

Non-blocking I/O uses channel.read(ByteBuffer ByteBuffer), while blocking I/O uses inputStream.read (byte b[]). If data cannot be read, blocking will continue. This is the fundamental difference between blocking AND non-blocking I/O

In general, a byteBuffer looks like this (\r, \n, \tRepresents the end of a line or paragraph of information, represented in this case by newlines and blank lines.)

The parsed request looks like this

Appendix: Representation of different body types in byteBuffer

form-data

This is the text in TXT formatexport.txtThe value inside is 123456, which has been resolved

x-www-form-urlencoded

raw

The transmission is of json type