我目前使用非阻塞的SocketChannel(Java 1.6)作为Redis服务器的客户端。 Redis直接通过套接字接受纯文本命令,以CRLF结尾,并以类似方式响应,以下是一个快速示例:
SEND:'PING\r\n' RECV:'+PONG\r\n'
Redis还可以返回巨大的回复(取决于您要求什么),其中包含许多以\r\n结尾的数据部分,所有这些部分都作为单个响应的一部分。
我使用标准的while(socket.read() > 0) {//append bytes}循环从套接字读取字节,并在客户端重新组装它们以形成回复。
注意:我没有使用Selector,只是连接到服务器并等待服务发送/接收命令的多个客户端SocketChannels。
我困惑的是非阻塞模式下SocketChannel.read()方法的契约,特别是如何知道服务器何时完成发送并且我拥有整个消息。
我有一些方法来防止过早返回并给服务器一个回复机会,但我卡在的一件事是:
1.是否可能read()返回字节,然后在随后的调用中不返回任何字节,但在另一个随后的调用中再次返回一些字节?
基本上,如果我已经收到至少1个字节并且最终read()返回0,则我知道我完成了,那么我可以相信服务器已经完成向我回复,还是可能服务器正忙,并且如果我等待并继续尝试,它可能会再次返回一些字节?
如果即使在read()返回0字节(在先前成功读取后)之后,它仍然可以继续发送字节,则我不知道如何告诉服务器何时完成与我交谈,实际上我甚至不知道java.io.*风格的通信如何知道服务器何时“完成”。
正如您所知,除非连接死亡,否则read永远不会返回-1,而这些都是标准的长期DB连接,因此我不会在每个请求上关闭和打开它们。
我知道一个流行的回答(至少对于这些NIO问题)是查看Grizzly、MINA或Netty——如果可能的话,在采用第三方依赖项之前,我真的想学习这一切在其原始状态下是如何工作的。
谢谢。
附加问题:
我最初认为阻塞的SocketChannel将是进行此操作的方法,因为我实际上不希望调用者做任何事情,直到我处理他们的命令并给他们回复。
如果这种方式更好,我有点困惑,因为SocketChannel.read()会阻塞,只要没有足够的字节填充给定的缓冲区...除非逐个字节地读取所有内容,否则我无法弄清楚这种默认行为实际上应该如何使用...我从不知道服务器返回的确切大小,因此我的SocketChannel.read()调用总是阻塞直到超时(此时我最终看到内容在缓冲区中)。
我不太清楚如何正确使用阻塞方法,因为它总是在读取时挂起。
SEND:'PING\r\n' RECV:'+PONG\r\n'
Redis还可以返回巨大的回复(取决于您要求什么),其中包含许多以\r\n结尾的数据部分,所有这些部分都作为单个响应的一部分。
我使用标准的while(socket.read() > 0) {//append bytes}循环从套接字读取字节,并在客户端重新组装它们以形成回复。
注意:我没有使用Selector,只是连接到服务器并等待服务发送/接收命令的多个客户端SocketChannels。
我困惑的是非阻塞模式下SocketChannel.read()方法的契约,特别是如何知道服务器何时完成发送并且我拥有整个消息。
我有一些方法来防止过早返回并给服务器一个回复机会,但我卡在的一件事是:
1.是否可能read()返回字节,然后在随后的调用中不返回任何字节,但在另一个随后的调用中再次返回一些字节?
基本上,如果我已经收到至少1个字节并且最终read()返回0,则我知道我完成了,那么我可以相信服务器已经完成向我回复,还是可能服务器正忙,并且如果我等待并继续尝试,它可能会再次返回一些字节?
如果即使在read()返回0字节(在先前成功读取后)之后,它仍然可以继续发送字节,则我不知道如何告诉服务器何时完成与我交谈,实际上我甚至不知道java.io.*风格的通信如何知道服务器何时“完成”。
正如您所知,除非连接死亡,否则read永远不会返回-1,而这些都是标准的长期DB连接,因此我不会在每个请求上关闭和打开它们。
我知道一个流行的回答(至少对于这些NIO问题)是查看Grizzly、MINA或Netty——如果可能的话,在采用第三方依赖项之前,我真的想学习这一切在其原始状态下是如何工作的。
谢谢。
附加问题:
我最初认为阻塞的SocketChannel将是进行此操作的方法,因为我实际上不希望调用者做任何事情,直到我处理他们的命令并给他们回复。
如果这种方式更好,我有点困惑,因为SocketChannel.read()会阻塞,只要没有足够的字节填充给定的缓冲区...除非逐个字节地读取所有内容,否则我无法弄清楚这种默认行为实际上应该如何使用...我从不知道服务器返回的确切大小,因此我的SocketChannel.read()调用总是阻塞直到超时(此时我最终看到内容在缓冲区中)。
我不太清楚如何正确使用阻塞方法,因为它总是在读取时挂起。