所以...我有一些软件应该与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
方法中翻转它不同。
我觉得这很奇怪。这可能或仅仅是掩盖了一个不同的错误吗?
答案 0 :(得分:0)
对于NIO,您应该始终检查是否已写入所有缓冲区,这是在第一个写入块中未执行的操作。话虽如此,除非写入大量数据,否则整个缓冲区通常只需一次调用write
即可。所以,这不太可能成为根本问题。
在替代编写代码块中,hasRemaining
条件被否定,它应该是:
while(msg.hasRemaining()) {
System.out.println("writing ...");
chan.write(msg);
}
你能先列出先发送的内容吗?第一个命令是否以\r\n
终止?