用java nio实现简易分布式缓存服务端:基于selector非阻塞通信,按行解析set/get/del/quit文本协议,每个socketchannel绑定独立bytebuffer处理半包粘包,使用concurrenthashmap线程安全存储,不依赖外部框架。

用 Java NIO 实现一个简易的分布式缓存服务端,核心是不依赖 Tomcat 或 Netty 等框架,纯 JDK 的 java.nio 包完成非阻塞网络通信 + 内存键值存储。它不适合生产,但能帮你深入理解 NIO 机制、协议设计和缓存服务本质。
一、定义简单文本协议(便于调试)
不用二进制或序列化,用换行分隔的纯文本命令,类似 Redis 的 RESP 简化版:
-
SET key value —— 存入(value 中若含空格,整体用双引号包裹,如
SET name "zhang san") -
GET key —— 查询,命中返回
VALUE value,未命中返回NOT_FOUND - DEL key —— 删除
- QUIT —— 关闭连接
每条命令以 \n 结尾,服务端按行解析,避免粘包问题(NIO 中需自己处理缓冲区边界)。
二、用 Selector + Channel 构建非阻塞服务端
关键步骤:
- 创建
ServerSocketChannel,设为非阻塞,绑定端口(如 8080) - 注册到
Selector,监听OP_ACCEPT - 在主循环中调用
selector.select(),有事件就处理:
• 是 accept 事件:接收新连接,SocketChannel设为非阻塞,注册OP_READ,并关联一个ByteBuffer用于读缓冲(每个 channel 独立)
• 是 read 事件:从 channel 读字节到 buffer,检查是否读到\n;若没读完,继续等待下一次 read;若读到完整一行,解析命令并执行,再把响应写回(注意 write 可能未写完,需注册OP_WRITE并在可写时继续) - 用
SelectionKey.attach()绑定每个 channel 对应的读缓冲区、待写内容等状态对象,避免全局 map 查找
三、内存缓存用 ConcurrentHashMap 实现线程安全
既然是“分布式缓存服务端”,多个客户端并发访问,必须保证读写安全:
- 声明
private static final Map<string string> cache = new ConcurrentHashMap();</string> - 所有
GET/SET/DEL操作直接调用cache.get()、cache.put()、cache.remove()即可,无需额外同步 - 不加过期、LRU、持久化——保持“简易”定位;如需扩展,可在 value 封装为
CacheEntry { value, expireAt },读取时判断过期
四、处理半包与粘包(NIO 最易出错点)
不能假设一次 read() 一定读到一整条命令。正确做法:
- 每个
SocketChannel对应一个ByteBuffer(如 1024 字节),初始flip()前先compact() - 每次 read 后,扫描 buffer 中是否有
\n(用buffer.array()配合position范围查找) - 找到 \n,截取从
buffer.position() - buffer.remaining()到该位置的字节数组,转成 String 解析命令;然后buffer.compact(),把未处理数据移到开头 - 找不到 \n,说明命令不完整,继续等待下次 read
示例片段(简化):
String line = StandardCharsets.UTF_8.decode(buffer).toString().trim(); // 注意只对已读部分解码不复杂但容易忽略细节——协议要简单、状态要绑定、缓冲要管理、并发要安全。写完约 300 行代码就能跑通 SET/GET/DEL 多客户端交互。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











