Ich habe einen Proxy-Server implementiert mit Netty, in dem ich HTTP-Anfragen decodiere und diese Anfragen dann basierend auf ihrem Pfad in einen ausgehenden Kanal schreibe. Ich muss einige Informationen aus dem Inhalt der HTTP-Anfrage extrahieren, um sie für zukünftige Verarbeitung zu verwenden (im Grunde genommen, eine Teilzeichenfolge der Form "request-id:" finden und für spätere Verwendung aufzeichnen. Was ist der beste Weg, dies zu tun? Offensichtlich könnte ich den Inhalt des Kanalpuffers in einen String schreiben und Standard-Java-String-Suchtechniken verwenden, aber gibt es einen einfachen und ressourcenschonenden Weg, dies in Netty zu tun, ohne einen neuen String zu erstellen? Zum Beispiel, wenn es so etwas wie eine asCharSequence(CharSet)
Methode für ChannelBuffer geben würde, könnte ich einfach ein Java Pattern/Matcher verwenden.
Antworten
Zu viele Anzeigen?Ich bin vor einer Weile auf dieses Problem gestoßen, als ich versuchte, den Inhaltstyp der Bytes innerhalb eines ChannelBuffer zu analysieren.
Es fiel mir ein, dass du folgendes verwenden könntest:
channelBuffer.toByteBuffer().asCharBuffer()
was du dann an einen Regex Pattern.Matcher übergeben könntest, da dabei der Puffer nicht neu alloziert wird, sondern nur umhüllt und neu repräsentiert wird, sozusagen. Aber das funktioniert nicht, weil der CharBuffer in Charset.decoded sein muss, was wahrscheinlich genauso schlecht ist wie das Umwandeln des ChannelBuffer in eine Zeichenkette.
Eines der Probleme bei ChannelBufferIndexFinder ist, dass es am besten funktioniert, wenn man nach einem bestimmten Byte sucht, während es beim Suchen nach einem String (oder einfach einem Byte-Array mit einer Länge > 1) nicht so funktioniert, wie ich es wollte.
Ich habe mit der Implementierung dieses ChannelBufferIndexFinder namens ByteSequenceIndexFinder begonnen, das dabei hilft, eine tatsächliche Byte-Folge innerhalb eines ChannelBuffer zu finden, aber es gibt ein paar Probleme damit:
- Da ChannelBuffer.bytesBefore(...) funktioniert, gibt es nicht den direkten Offset des gefundenen Arrays zurück, sondern nur das Ende davon, daher musst du die Länge des Byte-Arrays +1 vom zurückgegebenen Index subtrahieren, um den Offset des Beginns der Byte-Folge im Byte-Puffer zu erhalten.
- Da der Finder den Zustand (die Anzahl der bisher übereinstimmenden Bytes) speichern muss, ist er nicht threadsicher. Ich habe versucht, den einfachen Zustand (eines Integers) durch ein ThreadLocal zu ersetzen, aber die Leistung wurde drastisch reduziert, aber es bleibt eine Option.
Es gibt eigentlich eine alternative Aufrufmethode, die nicht standardmäßig ist und Problem #1 angeht und funktioniert wie folgt:
ChannelBuffer bufferToSearch = ...;
String searchStr = "....";
ByteSequenceIndexFinder finder = new ByteSequenceIndexFinder(searchStr.getBytes());
int startingOffset = finder.findIn(bufferToSearch);
Dieser StartingOffset ist der Offset des ersten Bytes der übereinstimmenden Byte-Folge innerhalb des Kanalpuffers.
Hoffentlich kann es dir hilfreich sein, wenn du so etwas benötigst. Hier ist der Anfang eines Testfalls dafür.
Ich verwende die folgende Implementierung von ChannelBufferIndexFinder
, um nach einem String in ChannelBuffer
zu suchen:
public class StringFinder implements ChannelBufferIndexFinder {
private String string;
public StringFinder(String string) {
this.string = string;
}
@Override
public boolean find(ChannelBuffer buffer, int guessedIndex) {
if (buffer.writerIndex() - guessedIndex < string.length()) {
return false;
}
return string.equals(buffer.toString(guessedIndex,
string.length(), Charset.defaultCharset()));
}
}