SwitNIO-接続Redis(一)
3689 ワード
先周、SwitNIOでプログラムを书いて、redisをキャッシュして、GitHubで探してみたらオープンソースライブラリがありましたが、使っていたらBugがあったので、作者にissueを提案してから今まで修复していません...だから自分で車輪を作って、ついでに勉強しました.
Redisクライアントを作るには、RESPプロトコルとredisコマンドの2つを理解する必要があります.
単一行文字列(Simple Strings)、先頭文字:'+' エラーメッセージ(Errors)、先頭文字は'-' 整形数字(Integers)、先頭文字は':' 複数行文字列(Bulk Strings)、先頭文字:'$' 配列(Arrays)、先頭文字:'*' 送信されたコマンドもredisサービス側からの返信も
Javaの方はJedis、NettyでNedisと書いてあるので、これをSedisと名付けました!
このクラスには、認証を含む
前にSwitNIOでUDP通信を確立することを書いたのですが、
ここでサービス側の返信を受信した後、何の操作もせずに直接出力します.
テスト実行
コンソール出力が表示されます
これで第1部はfinish
Redisクライアントを作るには、RESPプロトコルとredisコマンドの2つを理解する必要があります.
簡単な紹介RESP
"+OK\r
"
"-Error message\r
"
":0\r
"
"$6\r
foobar\r
"
"*2\r
$3\r
foo\r
$3\r
bar\r
"
\r
で終わることに注意してください.Javaの方はJedis、NettyでNedisと書いてあるので、これをSedisと名付けました!
まずstructを作成し、接続情報を格納します。
struct SedisOptions {
let prot: Int
let host: String
var password: String?
var database: Int?
}
次に、SedisClientクラスを作成します。
このクラスには、認証を含む
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 in
channel.pipeline.add(handler: RESPHandler())
})
}
private func _connect() -> EventLoopFuture {
assert(bootstrap != nil, "init failure")
return bootstrap!.connect(host: options.host, port: options.prot)
}
}
前にSwitNIOでUDP通信を確立することを書いたのですが、
DatagramBootstrap
を使っています.ここではクライアントとして接続する必要があるので、ClientBootstrap
を使っています.最後にRESPHandlerを追加
class RESPHandler: ChannelDuplexHandler {
typealias InboundIn = ByteBuffer
func channelRead(ctx: ChannelHandlerContext, data: NIOAny) {
var value = unwrapInboundIn(data)
print(value.readString(length: value.writerIndex))
}
}
ここでサービス側の返信を受信した後、何の操作もせずに直接出力します.
SedisClient
のinit
メソッドの末尾にテストコードを追加して、正常に通信できるかどうかをテストします.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 in
channel.pipeline.add(handler: RESPHandler())
})
let channel = try? _connect().wait()
let command = "set a 1\r
".utf8
var byteBuffer = ByteBufferAllocator().buffer(capacity: command.count)
byteBuffer.write(bytes: command)
channel?.writeAndFlush(byteBuffer, promise: nil)
try? channel?.closeFuture.wait()
}
テスト実行
let sdies = SedisClient(options: SedisOptions(prot: 6379, host: "127.0.0.1", password: nil, database: 0))
コンソール出力が表示されます
Optional("+OK\r
")
これで第1部はfinish