【发布时间】:2015-09-08 06:21:59
【问题描述】:
作为一些背景:
我通过 SocketChannel、SelectionKey...等连接到服务器。在客户端,如果我想向服务器发送一些东西,我只需将我的数据写入一个 ByteBuffer 并通过套接字通道发送。如果所有的都写好了,我就完成了,可以返回到 OP_READ。如果不是全部写入,我将剩余的字节取出,将它们存储在某处的“发送”缓冲区中,并在键上标记 OP_WRITE(替换 OP_READ 以便仅写入是个好主意吗?)。
因此,下次我调用 selectNow() 时,我假设它会识别 OP_WRITE 并尝试刷新更多数据(我将尝试通过进入另一个写入循环来写入数据,然后重复如果需要,可以上一个)。
这引出了两个问题:
- 我是否应该将其保留在 OP_WRITE 中,直到所有数据都被刷新?或者我应该更改为 OP_READ 并尝试在其间进行任何读取?
如果写作频道已满而我无法写作,我是否要一直循环直到我可以开始写作?如果连接突然被阻塞,我不确定我是否应该只写我能写的内容,返回到 OP_READ,尝试读取,然后返回到 OP_WRITE。根据我的阅读,这似乎不是正确的做事方式(并且可能会导致大量开销不断来回切换?)。
- 当缓冲区都可能已满时,处理读取和写入批量数据的最佳方法是什么?
读取听起来很容易,因为您只是循环直到数据被消耗,但是写入......服务器可能只写入而不读取。这会给你留下一个相当完整的发送缓冲区,并且在 OP_WRITE 上永远循环而不读取会很糟糕。你如何避免这种情况?如果发送缓冲区没有清除,您是否设置了一个计时器,您将在该计时器上停止尝试写入并再次开始读取?如果是这样,您是否删除 OP_WRITE 并记住它以备后用?
附带问题:您是否甚至需要 OP_READ 才能从网络读取?我不确定它是否像 OP_WRITE 一样,您只在特定情况下标记它(以防万一我做错了,因为我有 99.9% 的时间在 OP_READ 上)。
目前我只是将我的密钥设置为 OP_READ,然后将其置于该模式,等待数据,然后当且仅当写入失败发送所有数据时才转到 OP_WRITE(write() 值为 0)。
【问题讨论】:
-
我想我想看看一些(简化的)代码。你提到了 OP_WRITE 和
selectNow(),但没有提到Selector,只是SocketChannel,所以我真的很困惑你到底在做什么。 -
@markspace 它是如何令人困惑的?选择器是隐含的,你怎么称呼
selectNow()没有一个选择器?我的一些东西甚至不需要代码就可以回答,因为后半部分纯粹是概念性的。 -
即使使用代码,使用选择器也足够复杂。只有英文描述,我无法猜测实际发生了什么。如果其他人想猜测,请把自己打晕,但我不知道你真正想做什么/有什么问题。
-
@markspace 非常清楚。