上星期用SwiftNIO寫了一套程序,而後須要用到redis作緩存,而後就去GitHub上找了一下發現有一個開源庫,可是用的時候發現有Bug,向做者提了issue以後至今沒有修復... 因此就本身動手造了個輪子,順便學習一下。redis
要作redis客戶端的話有兩個東西必需要了解,RESP協議和redis命令。bootstrap
"+OK\r\n"
"-Error message\r\n"
":0\r\n"
"$6\r\nfoobar\r\n"
"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"
須要注意的是無論是發送的命令仍是收到來自redis服務端的回覆,都是以\r\n
結尾。數組
Java那邊的叫Jedis,用Netty寫的叫Nedis,那麼我就把這個命名爲Sedis了!promise
struct
,用來存儲鏈接信息:struct SedisOptions {
let prot: Int
let host: String
var password: String?
var database: Int?
}
複製代碼
這個類裏面須要根據SedisOptions
的信息來建立鏈接,包括身份驗證。緩存
class SedisClient {
private let options: SedisOptions
private var bootstrap: ClientBootstrap?
private var loopGroup: EventLoopGroup!
init(options: SedisOptions) {
self.options = options
loopGroup = MultiThreadedEventLoopGroup(numThreads: System.coreCount)
bootstrap = ClientBootstrap(group: loopGroup)
.channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET),
SO_REUSEADDR), value: 1)
.channelInitializer({ (channel) -> EventLoopFuture<Void> in
channel.pipeline.add(handler: RESPHandler())
})
}
private func _connect() -> EventLoopFuture<Channel> {
assert(bootstrap != nil, "init failure")
return bootstrap!.connect(host: options.host, port: options.prot)
}
}
複製代碼
以前寫了一遍用SwiftNIO創建UDP通信的,用的是DatagramBootstrap
,咱們這裏須要看成客戶端鏈接,因此用的是ClientBootstrap
。bash
RESPHandler
class RESPHandler: ChannelDuplexHandler {
typealias InboundIn = ByteBuffer
func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
var value = unwrapInboundIn(data)
print(value.readString(length: value.writerIndex))
}
}
複製代碼
這裏接收到服務端回覆後先不作任何操做直接輸出。socket
如今在SedisClient
的init
方法末尾加上一段測試代碼測試是否能正常通信oop
init(options: SedisOptions) {
self.options = options
loopGroup = MultiThreadedEventLoopGroup(numThreads: System.coreCount)
bootstrap = ClientBootstrap(group: loopGroup)
.channelOption(ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET),
SO_REUSEADDR), value: 1)
.channelInitializer({ (channel) -> EventLoopFuture<Void> in
channel.pipeline.add(handler: RESPHandler())
})
let channel = try? _connect().wait()
let command = "set a 1\r\n".utf8
var byteBuffer = ByteBufferAllocator().buffer(capacity: command.count)
byteBuffer.write(bytes: command)
channel?.writeAndFlush(byteBuffer, promise: nil)
try? channel?.closeFuture.wait()
}
複製代碼
測試運行post
let sdies = SedisClient(options: SedisOptions(prot: 6379, host: "127.0.0.1", password: nil, database: 0))
複製代碼
能夠看到控制檯輸出學習
Optional("+OK\r\n")
複製代碼
至此,第一部分就已經finish