Analyze the source code entry
LineBasedFrameDecoder is a line-level decoder that uses \n or \r\n as delimiters. Let’s first look at its class structure diagram:
When we talked about channelRead, we ended up calling the decode method of the subclass, and we went straight to decode the code!
Second, source code analysis
protected Object decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
// Find the position at the end of the line where \n or \r is returned
final int eol = findEndOfLine(buffer);
if(! discarding) {// There is an end
if (eol >= 0) {
final ByteBuf frame;
// End position - both pointer position = valid data length
final int length = eol - buffer.readerIndex();
// If the current index points to \r, the proof is that the end starts with \r\n. The data takes up two bytes; otherwise it takes up one
final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
// If the valid data length is larger than the preset length, an error is reported and discarded
if (length > maxLength) {
// Reposition the read pointer
buffer.readerIndex(eol + delimLength);
// An error is reported
fail(ctx, length);
return null;
}
// Whether to discard newlines
if (stripDelimiter) {
// If set to discard, slice from the current pointer position and increase the reference count
ReadSlice ().retain()
frame = buffer.readRetainedSlice(length);
// Skip newline character \n skip one \r\n skip two
buffer.skipBytes(delimLength);
} else {
// Read the valid length of data from the current read pointer position + newline length position
frame = buffer.readRetainedSlice(length + delimLength);
}
// Return this slice
return frame;
} else {
// Current valid data
final int length = buffer.readableBytes();
if (length > maxLength) {
discardedBytes = length;
buffer.readerIndex(buffer.writerIndex());
discarding = true;
offset = 0;
if (failFast) {
fail(ctx, "over "+ discardedBytes); }}// do no processing
return null; }}else{... Ignore...return null; }}Copy the code
1. Look for the end of the line
final int eol = findEndOfLine(buffer);
Copy the code
/** * returns the index in the found end-of-line buffer. * If no line end is found in the buffer, -1 is returned. * /
private int findEndOfLine(final ByteBuf buffer) {
// Get the length of readable bytes
int totalLength = buffer.readableBytes();
// Query from current read pointer + offset position to maximum readable - offset position query \n
int i = buffer.forEachByte(buffer.readerIndex() + offset, totalLength - offset, ByteProcessor.FIND_LF);
// if there is \n
if (i >= 0) {
// Initialize the offset
offset = 0;
// If the newline character is preceded by \r, the position of \r is returned
if (i > 0 && buffer.getByte(i - 1) = ='\r') { i--; }}else {
// If no query is found, the current offset is recorded and moved to the end of the data to wait for the next data read
offset = totalLength;
}
return i;
}
Copy the code
int i = buffer.forEachByte(buffer.readerIndex() + offset, totalLength - offset, ByteProcessor.FIND_LF);
Copy the code
Select * from ByteBuf, select * from ByteBuf, select * from ByteBuf, select * from ByteBuf, select * from ByteBuf, select * from ByteBuf; If not found, return -1, interested partners can follow, here do not do too much explanation!
// Initialize the offset
offset = 0;
// If the newline character is preceded by \r, the position of \r is returned
if (i > 0 && buffer.getByte(i - 1) = ='\r') {
i--;
}
Copy the code
If there is \n, look ahead one bit to see if it is **\r**. If so, prove that the packet ended in **\r\n**, we set the index to the position \r!
If it does not end with \n then else logic is entered:
offset = totalLength;
Copy the code
Record an offset directly for this read, so that next time you can go back and find \n!
2. Intercept data
If the returned data exists \n proof is existential end, enter the if logic!
// position of \n or \r - read pointer position = effective data length of complete packet
final int length = eol - buffer.readerIndex();
Copy the code
Figure out the effective length of the data first!
// If the current index points to \r, the proof is that the end starts with \r\n. The data takes up two bytes; otherwise it takes up one
final int delimLength = buffer.getByte(eol) == '\r'? 2 : 1;
Copy the code
Determine what the end is. If the end is \n, prove that the length of the separator is 1. If it ends in \r\n, prove that the length is 2!
if (length > maxLength) {
// Reposition the read pointer
buffer.readerIndex(eol + delimLength);
// An error is reported
fail(ctx, length);
return null;
}
Copy the code
This determines whether the current valid data exceeds the maximum length set by the constructor. If so, discard the data (move the read pointer back to the end of the data), and then report an error!
// Whether to discard newlines
if (stripDelimiter) {
// If set to discard, slice from the current pointer position and increase the reference count
ReadSlice ().retain()
frame = buffer.readRetainedSlice(length);
// Skip newline character \n skip one \r\n skip two
buffer.skipBytes(delimLength);
} else {
// Read the valid length of data from the current read pointer position + newline length position
frame = buffer.readRetainedSlice(length + delimLength);
}
Copy the code
To determine whether to discard the newline character, which is the argument passed to the LineBasedFrameDecoder, the default is true;
If discard line breaks is set:
- Call the readRetainedSlice method to slice a complete packet (without newlines) backwards from the current read pointer position from the current complete packet!
- Call skip method, skip the newline, so that the read pointer must be behind the packet!
If discard newline is false:
- Cut a valid length of data directly from the current complete packet + the length of the newline data! Similar: the existence of data \n, this is not need to skip!
So far, we have got a complete packet according to the newline character, we just need to return it, and then abstract class ByteToMessageDecoder, it will return the data will be added to the out collection, waiting for processing!
Third, summary
- Every byte of the packet is iterated first! Find the index position of the first newline character!
- From the complete packet, from the beginning of the pointer to the end!