我建议使用 Apache Mina 或 Grizzly 之类的东西。两者都允许您封装问题的协议方面,因此您只需要处理可消耗的数据。
但是,如果您想要一种快速而肮脏的方式:基本的想法是,您需要读取传入的数据。如果它不容易使用,我通常会为 SelectionKey 创建一些可附加的结构(简单的 StringBuilder)在选择器中。每次读取后,我会将数据附加到构建器,如果您检测到可用的标头,请将其从缓冲区中切出并将其向上传递(最好在工作线程上)。继续这样做,上游的任何东西都应该能够做出相应的反应。希望有帮助。
所以通常你有这样的结构:
ByteBuffer reUsableBuffer = ByteBuffer.allocateDirect(5120);
Selector selector = Selector.open();
ServerSocketChannel channel = .. // wherever you get it from
channel.register(selector, SelectionKey.OP_ACCEPT);
Executor executor = Executors.newThreadPoolExecutor();
while(selector.isOpen()) {
int numKey = selector.select();
for (SelectionKey key: selector.selectedKeys()) {
if (key.isAcceptable()) {
/// Sort of included for completeness but you get the idea
ServerSocketChannel server = (ServerSocketChannel)key.channel();
SocketChannel channel = server.accept();
channel.register(selector, SelectionKey.OP_READ | Selection.OP_WRITE, new StringBuilder());
} if (key.isReadable()) {
// READ the data
reUsableBuffer.clear();
// You have to keep track of previous state.
// NIO makes no guarantees of anything
StringBuilder builder = key.attachment();
SocketChannel socketChannel = (SocketChannel)key.channel();
int readCount = socketChannel.read(reUsableBuffer);
if (readCount > 0) {
reUsableBuffer.flip();
byte[] subStringBytes = new byte[readCount];
reUsableBuffer.read(subStringBytes);
// Assuming ASCII (bad assumption but simplifies the example)
builder.append(new String(substringBytes));
Command[] commands = removeCommands(builder);
// Deal with your commands in some async manor defined by you
executor.execute(new Task(commands));
}
}
selector.selectedKeys().clear(); } ....
}
//
// Parse out the commands and return them, also remove traces of them in the
// the builder, such that for a string, "COMMAND, COMMAND, COM"
// an array of 2 should be returned with a left over buffer of "COM"
public Command[] parseCommands(StringBuilder s) { ... }