Java,Memcached - 如何将命令传递给服务器?

时间:2016-10-06 12:35:31

标签: java connection memcached nio

所以...我有一些软件应该与memcached服务器通信(不使用外部库)。

出于测试目的,让我们选择一个简单的get hello\r\n命令。

我使用-vv选项启动memcached,这是命令通过telnet生成的内容:

<15 new auto-negotiating client connection
15: Client using the ascii protocol
<15 get hello
>15 END

现在,我的软件发出的命令就是:

<15 new auto-negotiating client connection

我按以下方式连接:

    private void reconnect(){
        InetSocketAddress remote;
        int nofServers = m.servers.size();
        for(int i = 0; i < R; ++i){
            boolean success = false;
            while(!success) {
                try {
                    SocketChannel oldConnection = connections.get(i);
                    if (oldConnection != null) oldConnection.close();

                    remote = m.servers.get((myServerIndex + i) % nofServers).address();
                    SocketChannel chan = SocketChannel.open(remote);
                    chan.configureBlocking(false);
                    chan.register(this.selector, SelectionKey.OP_READ);
                    connections.set(i, chan);
                    success = true;
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

之后,该软件就变得非常简单了NIO循环:

    @Override
    public void run() {
        MyRequest curr = null;
        this.canHandleNewRequest = true;
        while (true) {
            if (canHandleNewRequest) {
                curr = myQueue.poll();
            }
            if (canHandleNewRequest && curr != null) {
                canHandleNewRequest = false;
                for (int i = 0; i < R; ++i) {
                    connections.get(i).keyFor(this.selector).interestOps(SelectionKey.OP_WRITE);
                }
            }

            try {
                selector.select();
                Iterator<SelectionKey> it = selector.selectedKeys().iterator();
                while (it.hasNext()) {
                    SelectionKey k = it.next();
                    it.remove();

                    if (!k.isValid()) continue;
                    if (k.isConnectable()) finishConnection(k);
                    else if (k.isReadable()) this.read(k, curr);
                    else if (k.isWritable()) this.write(k, curr);
                }
            } catch (IOException ex) {
                ex.printStackTrace();
                reconnect();
            }

            if(curr != null && /*have sent to all servers I need to*/){
                curr = null;
                this.canHandleNewRequest = true;
            }
        }
    }

,其中

    private void write(SelectionKey k, MyRequest currentRequest){
        try {
            SocketChannel chan = (SocketChannel) k.channel();
            ByteBuffer out = currentRequest.getSendBuffer(); //DO NOT FLIP (to resume sending from last sent position)
            assert(chan != null);
            assert(out != null);
            //System.out.println(new String(out.array()));
            chan.write(out); //TODO: make this work!

            if(!out.hasRemaining()) { //do not enable read until whole command has been sent
                currentRequest.partiallySent();
                k.interestOps(SelectionKey.OP_READ);
            }

        }catch(IOException ex){
            ex.printStackTrace();
        }

        //TODO: create response structure
    }

我甚至尝试用write方法替换伪命令提供程序:

else if(k.isWritable()){
    SocketChannel chan = (SocketChannel)k.channel();
    ByteBuffer msg = ByteBuffer.wrap("get hello\r\n".getBytes());
    msg.flip();

    while(msg.hasRemaining()) {
        System.out.println("writing ...");
        chan.write(msg);
    }
    k.interestOps(SelectionKey.OP_READ);
}

但这只会陷入&#34;写作&#34;循环(永不终止)。

您应该认为至少服务器应该对该命令作出反应,但它不会。

所以...我该如何运作?

通过telnet提供命令的日志中的第二行产生,

15: Client using the ascii protocol

让我觉得在参与实际的memcached命令之前我可能需要向服务器发送一些东西...除了我似乎在the protocol中遗漏它。

帮助将不胜感激。

修改

这似乎是个问题:在getSendBuffer方法中翻转缓冲区然后返回它与将其解压缩然后在write方法中翻转它不同。

我觉得这很奇怪。这可能或仅仅是掩盖了一个不同的错误吗?

1 个答案:

答案 0 :(得分:0)

对于NIO,您应该始终检查是否已写入所有缓冲区,这是在第一个写入块中未执行的操作。话虽如此,除非写入大量数据,否则整个缓冲区通常只需一次调用write即可。所以,这不太可能成为根本问题。

在替代编写代码块中,hasRemaining条件被否定,它应该是:

while(msg.hasRemaining()) {
    System.out.println("writing ...");
    chan.write(msg);
}

你能先列出先发送的内容吗?第一个命令是否以\r\n终止?