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>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<artifactId>netty-codec-memcache</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>${project.groupId}</groupId>
|
||||
<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