Add a Example for Memcache Binary Codec
Motivation: Currently, there exists no example which shows how to use the memcache binary protocol. Modifications: Add an example client and client handler to show how to utilize the binary protocol in a memcache client with a simple interactive shell. Result: Users looking for an example can now start off with the provided one.
This commit is contained in:
parent
ad955fa8a4
commit
7a6fa73989
@ -53,6 +53,11 @@
|
|||||||
<artifactId>netty-codec-http</artifactId>
|
<artifactId>netty-codec-http</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>${project.groupId}</groupId>
|
||||||
|
<artifactId>netty-codec-memcache</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>${project.groupId}</groupId>
|
<groupId>${project.groupId}</groupId>
|
||||||
<artifactId>netty-codec-socks</artifactId>
|
<artifactId>netty-codec-socks</artifactId>
|
||||||
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.example.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.bootstrap.Bootstrap;
|
||||||
|
import io.netty.channel.Channel;
|
||||||
|
import io.netty.channel.ChannelFuture;
|
||||||
|
import io.netty.channel.ChannelInitializer;
|
||||||
|
import io.netty.channel.ChannelPipeline;
|
||||||
|
import io.netty.channel.EventLoopGroup;
|
||||||
|
import io.netty.channel.nio.NioEventLoopGroup;
|
||||||
|
import io.netty.channel.socket.SocketChannel;
|
||||||
|
import io.netty.channel.socket.nio.NioSocketChannel;
|
||||||
|
import io.netty.handler.codec.memcache.binary.BinaryMemcacheClientCodec;
|
||||||
|
import io.netty.handler.codec.memcache.binary.BinaryMemcacheObjectAggregator;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple memcache client that demonstrates get and set commands against a memcache server.
|
||||||
|
*/
|
||||||
|
public class MemcacheClient {
|
||||||
|
|
||||||
|
private final String host;
|
||||||
|
private final int port;
|
||||||
|
|
||||||
|
public MemcacheClient(String host, int port) {
|
||||||
|
this.host = host;
|
||||||
|
this.port = port;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() throws Exception {
|
||||||
|
EventLoopGroup group = new NioEventLoopGroup();
|
||||||
|
try {
|
||||||
|
Bootstrap b = new Bootstrap();
|
||||||
|
b.group(group)
|
||||||
|
.channel(NioSocketChannel.class)
|
||||||
|
.handler(new ChannelInitializer<SocketChannel>() {
|
||||||
|
@Override
|
||||||
|
protected void initChannel(SocketChannel ch) throws Exception {
|
||||||
|
ChannelPipeline p = ch.pipeline();
|
||||||
|
p.addLast(new BinaryMemcacheClientCodec());
|
||||||
|
p.addLast(new BinaryMemcacheObjectAggregator(Integer.MAX_VALUE));
|
||||||
|
p.addLast(new MemcacheClientHandler());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Start the connection attempt.
|
||||||
|
Channel ch = b.connect(host, port).sync().channel();
|
||||||
|
|
||||||
|
// Read commands from the stdin.
|
||||||
|
System.out.println("Enter commands (quit to end)");
|
||||||
|
System.out.println("get <key>");
|
||||||
|
System.out.println("set <key> <value>");
|
||||||
|
ChannelFuture lastWriteFuture = null;
|
||||||
|
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||||||
|
for (;;) {
|
||||||
|
String line = in.readLine();
|
||||||
|
if (line == null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ("quit".equals(line.toLowerCase())) {
|
||||||
|
ch.close().sync();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Sends the received line to the server.
|
||||||
|
lastWriteFuture = ch.writeAndFlush(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait until all messages are flushed before closing the channel.
|
||||||
|
if (lastWriteFuture != null) {
|
||||||
|
lastWriteFuture.sync();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
group.shutdownGracefully();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
// Print usage if no argument is specified.
|
||||||
|
if (args.length != 2) {
|
||||||
|
System.err.println(
|
||||||
|
"Usage: " + MemcacheClient.class.getSimpleName() +
|
||||||
|
" <host> <port>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse options.
|
||||||
|
String host = args[0];
|
||||||
|
int port = Integer.parseInt(args[1]);
|
||||||
|
|
||||||
|
new MemcacheClient(host, port).run();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2014 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
package io.netty.example.memcache.binary;
|
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf;
|
||||||
|
import io.netty.buffer.Unpooled;
|
||||||
|
import io.netty.channel.ChannelDuplexHandler;
|
||||||
|
import io.netty.channel.ChannelHandlerContext;
|
||||||
|
import io.netty.channel.ChannelPromise;
|
||||||
|
import io.netty.handler.codec.memcache.binary.BinaryMemcacheOpcodes;
|
||||||
|
import io.netty.handler.codec.memcache.binary.BinaryMemcacheRequest;
|
||||||
|
import io.netty.handler.codec.memcache.binary.DefaultBinaryMemcacheRequest;
|
||||||
|
import io.netty.handler.codec.memcache.binary.DefaultFullBinaryMemcacheRequest;
|
||||||
|
import io.netty.handler.codec.memcache.binary.FullBinaryMemcacheResponse;
|
||||||
|
import io.netty.util.CharsetUtil;
|
||||||
|
|
||||||
|
public class MemcacheClientHandler extends ChannelDuplexHandler {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms basic string requests to binary memcache requests
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||||
|
String command = (String) msg;
|
||||||
|
if (command.startsWith("get ")) {
|
||||||
|
String key = command.substring("get ".length());
|
||||||
|
|
||||||
|
BinaryMemcacheRequest req = new DefaultBinaryMemcacheRequest(key);
|
||||||
|
req.setOpcode(BinaryMemcacheOpcodes.GET);
|
||||||
|
req.setKeyLength((short) key.length());
|
||||||
|
req.setTotalBodyLength(key.length());
|
||||||
|
|
||||||
|
ctx.write(req, promise);
|
||||||
|
} else if (command.startsWith("set ")) {
|
||||||
|
String[] parts = command.split(" ", 3);
|
||||||
|
if (parts.length < 3) {
|
||||||
|
throw new IllegalArgumentException("Malformed Command: " + command);
|
||||||
|
}
|
||||||
|
String key = parts[1];
|
||||||
|
String value = parts[2];
|
||||||
|
|
||||||
|
ByteBuf content = Unpooled.wrappedBuffer(value.getBytes(CharsetUtil.UTF_8));
|
||||||
|
ByteBuf extras = ctx.alloc().buffer(8);
|
||||||
|
|
||||||
|
BinaryMemcacheRequest req = new DefaultFullBinaryMemcacheRequest(key, extras, content);
|
||||||
|
req.setOpcode(BinaryMemcacheOpcodes.SET);
|
||||||
|
req.setKeyLength((short) key.length());
|
||||||
|
req.setExtrasLength((byte) 8);
|
||||||
|
req.setTotalBodyLength(key.length() + 8 + value.length());
|
||||||
|
|
||||||
|
ctx.write(req, promise);
|
||||||
|
} else {
|
||||||
|
throw new IllegalStateException("Unknown Message: " + msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
|
||||||
|
FullBinaryMemcacheResponse res = (FullBinaryMemcacheResponse) msg;
|
||||||
|
System.out.println(res.content().toString(CharsetUtil.UTF_8));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||||
|
cause.printStackTrace();
|
||||||
|
ctx.close();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user