1. Введение в библиотеку NIO
1. Буферный буфер
Буфер - это объект, который содержит некоторые данные, которые будут записаны и прочитаны.
В NIO все данные обрабатываются в буфере. При чтении данных он читается непосредственно из канала в буфер, а при написании данных также записывается из буфера на канал.
Буфер, по сути, представляет собой массив, обычно массив байтов (байтбаффер) или другие типы массивов. Кроме того, буфер также предоставляет такую информацию, как структурированный доступ к данным и поддержание местоположений чтения и записи.
Взаимосвязь наследования класса буфера показана на рисунке ниже:
2. Канал
Канал - это канал, где сетевые данные читаются и записываются через канал. Разница между каналом и потоком заключается в том, что канал является двунаправленным (канал можно использовать для чтения и записи последнего одновременно), а поток движется только в одном направлении.
Каналы могут быть примерно разделены на две категории: SelectableChannel для считывания и написания сети (Serversocketchannel и Socketchannel являются их подклассами) и FileChannel для операций файлов.
В следующем примере показан файл с использованием FileChannel для записи данных в файл, прочитать данные из файла и скопировать данные файла в другой файл:
открытый класс niotest {public static void main (string [] args) бросает ioException {copyFile (); } // Скопируйте файл private static void copyFile () {fileInputStream in = null; FileOutputStream OUT = null; try {in = new FileInputStream ("src/main/java/data/in data.txt"); out = new FileOutputStream ("src/main/java/data/out data.txt"); FileChannel Inchannel = in.getChannel (); FileChannel OutChannel = out.getChannel (); Bytebuffer buffer = bytebuffer.allocate (1024); int bytesread = inchannel.read (buffer); while (bytesread! =-1) {buffer.flip (); OutChannel.Write (буфер); buffer.clear (); bytesread = inchannel.read (buffer); }} catch (filenotfoundexception e) {// todo автоматически сгенерированный блок e.printstacktrace (); } catch (ioException e) {// todo автоматически сгенерированный блок e.printstacktrace (); }} // записать файл private static void writefilenio () {try {randomAccessfile fout = new randomAccessfile ("src/main/java/data/nio-data.txt", "rw"); FileChannel fc = fout.getChannel (); Bytebuffer buffer = bytebuffer.allocate (1024); buffer.put ("hi123" .getbytes ()); buffer.flip (); try {fc.write (buffer); } catch (ioException e) {// todo автоматически сгенерированный блок e.printstacktrace (); }} catch (filenotfoundexception e) {// todo автоматически сгенерированный блок e.printstacktrace (); }} // Читать файл private static void readfilenio () {fileInputStream fileInputStream; try {fileInputStream = new FileInputStream ("src/main/java/data/nio-data.txt"); FileChannel fileChannel = fileInputStream.getChannel (); // Получить канал FileInputStream bytebuffer bytebuffer = bytebuffer.allocate (1024); // Создать буфер int bytesread = fileChannel.read (bytebuffer); // Читать данные в буферу, когда (bytesread! */ bytebuffer.flip (); // hasreming (): сообщите, существует ли элемент между текущей позицией и пределом, пока (bytebuffer.hasreming ()) {System.out.print ((char) bytebuffer.get ()); } /** Очистить буфер* position = 0; * Limit = емкость; */ bytebuffer.clear (); bytesread = fileChannel.read (bytebuffer); }} catch (filenotfoundexception e) {// todo автоматически сгенерированный блок e.printstacktrace (); } catch (ioException e) {// todo автоматически сгенерированный блок e.printstacktrace (); }}}3. Селектор мультиплексоров
Мультиплексор предоставляет возможность выбирать задачи, которые готовы. Селектор будет постоянно опросить канал, зарегистрированный на нем. Если канал отправляет событие чтения или записи, канал будет в состоянии готового и будет опробован селектором. Затем набор готовых каналов может быть получен через SelectionKey для выполнения последующих операций ввода -вывода.
Селектор мультиплексоров может одновременно опросить несколько каналов. Поскольку JDK использует Epoll вместо традиционной реализации Select, он не имеет предела максимального контроля подключения 1024/2048, что означает, что только один поток должен нести ответственность за опрос селектора и может получить доступ к тысячам клиентов. Модель показана на рисунке ниже:
Обработайте селектор с одним потоком. Чтобы использовать селектор, вы должны зарегистрировать канал с помощью селектора, а затем вызовать его метод select (). Этот метод будет блокироваться до тех пор, пока зарегистрированный канал не будет готовым. Как только этот метод вернется, поток может обрабатывать эти события, такие как новые соединения, прием данных и т. Д.
Примечание:
1. Какая модель выбора?
SELECT - это механизм запуска событий, который запускает обработку при возникновении события ожидания, и в основном используется для обработки клиента в результате реализации серверов Linux.
Он может одновременно обнаружить набор неблокирующих устройств ввода-вывода, которые поддерживают не блокировку, независимо от того, есть ли события (такие как читаемые, записываемые, вывод с высоким приоритетом и т. Д.) До тех пор, пока устройство не запустит событие или не превышает указанное время ожидания. То есть их ответственность состоит не в том, чтобы сделать IO, а помочь звонящему найти в настоящее время готовое устройство.
2. Что такое модель Epoll?
Конструктивная идея Epoll состоит в том, чтобы разделить единственную операцию Select/Poll на 1 epoll_create + несколько epoll_ctrl + One ожидание. Кроме того, ядро добавило файловую систему «EventPollfs» для операций Epoll. Каждое или более дескрипторов файлов, которые должны быть отслежены, имеют узел INODE соответствующей файловой системы EventPollFS, а основная информация хранится в структуре EventPoll. Важная информация контролируемых файлов хранится в структуре эпитим. Таким образом, это отношения с одним ко многим.
2. Разработка на стороне сервера NIO
Описание функции: Включите сторону сервера и отправьте Hello String в каждом клиенте Access.
Есть несколько основных шагов для использования NIO для разработки на стороне сервера:
1. Создать Serversocketchannel и настроить его в режиме без блокировки
serversocketchannel = serversocketchannel.open (); Serversocketchannel.configureblocking (false);
2. Привяжите прослушивание и настройку параметров TCP, таких как размер отставания
serversocketchannel.socket (). Bind (new InetsocketAddress (8080));
3. Создайте независимую поток ввода -вывода для опроса селектора мультиплексоров
4. Создайте селектор, зарегистрируйте серверный канал, который вы создали ранее для селектора, и прослушивайте SelectionKey.accep
selector = selector.open (); serversocketchannel.register (selector, selectionkey.op_accte);
5. Запустите поток ввода/вывода, выполните метод SELECTER.Select () в корпусе петли и опросите готовый канал
В то время как (true) {try {// select () блокируется, пока не будет готово, по крайней мере, один канал не будет готов в зарегистрированном вами событии // Если не будет готово канала, он будет блокировать здесь // select (длительный тайм -аут), такой же, как и Select (), за исключением того, что он будет блокировать время -аут миллисекунд (параметры). selector.select (); } catch (ioException e) {// todo автоматически сгенерированный блок e.printstacktrace (); перерыв; }}6. При опросе канала в готовом состоянии необходимо судить. Если это состояние OP_ACCEPT, это означает, что это новый клиент -доступ. Затем вызовите метод Serversocketchannel.accept (), чтобы принять нового клиента.
// вернуть готовый выбор, а затем итерация, чтобы выполнить SET <SelectionKey> readKeys = selector.selectedKeys (); for (iterator <selectionkey> it = readkeys.iterator (); it.hasnext ();) {selectionKey key = it.next (); it.remove (); try {if (key.isaceceptable ()) {serversocketchanne server = (serversocketchannel) key.channel (); Socketchannel client = server.accept (); client.configureblocking (false); client.register (selector, selectionkey.op_write); } else if (key.iswrite ()) {socketchannel client = (socketchannel) key.channel (); Bytebuffer buffer = bytebuffer.allocate (20); String str = "hello"; buffer = bytebuffer.wrap (str.getbytes ()); client.write (buffer); key.cancel (); }} catch (ioException e) {e.printstacktrace (); key.cancel (); try {key.channel (). close (); } catch (ioException e1) {// todo автоматически сгенерированный блок e1.printstacktrace (); }}}7. Установите недавно доступный клиентский носок канала в неблокирующем режиме и настройте некоторые другие параметры TCP.
if (key.isaceceptable ()) {serversocketchannel server = (sergercocketchannel) key.channel (); Socketchannel client = server.accept (); client.configureblocking (false); ...}8. Зарегистрируйте Socketchannel to Selector и прослушайте Op_Write
client.register (selector, selectionkey.op_write);
9. Если опрошенный канал является Op_Write, это означает, что данные должны быть записаны в SockChannel, то объект ByteBuffer построен и записан пакет данных.
else if (key.iswrite ()) {socketchannel client = (socketchannel) key.channel (); Bytebuffer buffer = bytebuffer.allocate (20); String str = "hello"; buffer = bytebuffer.wrap (str.getbytes ()); client.write (buffer); key.cancel (); }Полный код заключается в следующем:
Импорт java.io.ioexception; import java.net.inetsocketAddress; импорт java.nio.bytebuffer; импорт java.nio.channels.selectionkey; импорт java.nio.channels.selector; import java.nio.channels.selector java.nio.channels.socketchannel; import java.util.iterator; import java.util.set; public class serversocketchanneldemo {public static void main (string [] args) {serversockencel Serversocketchannel; Selector Selecter = null; try {sergrocketchannel = ServerSocketChannel.open (); Serversocketchannel.configureBlocking (false); serversocketchannel.socket (). Bind (new InetSocketAddress (8080)); selector = selector.open (); serversocketchannel.register (selector, selectionkey.op_accept); blocke.printstacktrace ();} while (true) {try {// select () блокирует, пока не будет готово, по крайней мере, один канал не будет готов в случае зарегистрированного, которое вы зарегистрировали // Если не будет готово канала, он будет блокировать здесь все время .//select( -tameout) такой же, как и Select (), за исключением того, что он будет блокировать Timeout Millseconds (параметрии). selector.select ();} catch (ioexception e) {// todo автоматически сгенерированный слой blocke.printstacktrace (); break;} // возвращать готовый селекция, а затем итерация для выполнения set <letectionkey> readkeys = selector.selectedkeys (); для (iterator <selectionkey> it = readkeys. {SelectionKey key = it.next (); it.remove (); try {if (key.isceptable ()) {serversocketchannel server = (serversocketchannel) key.channel (); socketchannel client = server.accept (); client.configureblocking (false); client.register (selctor.op_write); {Socketchannel client = (socketchannel) key.channel (); bytebuffer buffer = bytebuffer.allocate (20); string str = "hello"; buffer = bytebuffer.wrap (str.getbytes ()); client.write (buffer); key.cancel ();} atear (ioexcret e); {e.printstacktrace (); key.cancel (); try {key.channel (). close ();} catch (ioexception e1) {// todo автоматически сгенерированный слок1.printstacktrace ();}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}Мы используем Telnet LocalHost 8080 для моделирования нескольких клиентов:
Результаты прогона программы следующие:
Суммировать
Выше приведено все подробное объяснение разработки на стороне сервера Java Nio в этой статье, я надеюсь, что это будет полезно для всех. Заинтересованные друзья могут продолжать ссылаться на другие связанные темы на этом сайте. Если есть какие -либо недостатки, пожалуйста, оставьте сообщение, чтобы указать это. Спасибо, друзья, за вашу поддержку на этом сайте!