Като малко предистория:
Имам връзка към сървър с 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, където го маркираш само в конкретен случай (само в случай, че го правя погрешно, тъй като го имам на OP_READ 99,9% от времето).
В момента просто задавам ключа си на OP_READ и след това го оставям в този режим, чакайки данни, и след това отивам на OP_WRITE, ако и само ако записът не успее да изпрати всички данни (със стойност на write() 0).
selectNow()
, но неSelector
, а самоSocketChannel
, така че наистина съм объркан какво, по дяволите, правите. - person markspace   schedule 22.06.2015selectNow()
без селектор? На някои от нещата ми може да се отговори, без дори да е необходим код, тъй като втората половина е чисто концептуална. - person Water   schedule 22.06.2015