Отсканируйте QR-код ниже или WeChat, чтобы найти официальную учетную запись.
菜鸟飞呀飞
, вы можете следить за публичной учетной записью WeChat, читать дальшеSpring源码分析
а такжеJava并发编程
статья.
предисловие
В начале года я поставил перед собой цель изучить исходный код Netty, поэтому в OKR Q2 одна из целей — изучить исходный код Netty и провести связанное с Netty совместное обучение в отделении. Однако рожденные телята не боятся тигров, в то время я даже не знал, как использовать Netty, а только смотрел исходный код. К концу второго квартала мой прогресс в обучении Netty был почти равен нулю. В OKR Q3 снова была поставлена цель посмотреть исходный код Netty, Потом, на протяжении Q3, этот лозунг по-прежнему просто выкрикивался в устах и ни разу не предпринимался. В 4 квартале цель изучения исходного кода Netty все еще записана в OKR. Учитывая, что до 4 квартала остался еще один месяц, результат обучения исходного кода Netty по-прежнему равен 0. После двух последовательных нарушений доверия я выкрикивал лозунги в течение двух кварталов выше Q2 и Q3.Как говорится, есть только три вещи, и я, наконец, решил написать анализ исходного кода, связанный с Netty.
Совмещая с собственным опытом изучения Netty, когда я официально вошел в анализ исходного кода Netty, я решил, что необходимо рассказать о взаимосвязи между BIO и NIO. В обычной работе я редко пишу код сетевого программирования напрямую, даже если я хочу его написать, я всегда использую зрелую сетевую структуру и редко занимаюсь программированием Socket напрямую. Далее будет объединен демонстрационный пример, чтобы ознакомиться со знаниями сетевого программирования. В демонстрационном примере клиент отправляет на сервер сообщение Hello World каждые три секунды, и сервер распечатывает его после получения.
BIO
BIO блокирует ввод-вывод, также известный как традиционный ввод-вывод.В сетевом программировании Java это относится к сетевому взаимодействию, реализованному с помощью ServerSocket и Socket socket.Это также класс, связанный с сетевым программированием, с которым мы столкнулись, когда впервые изучали Java. Сервер блокирует основной поток, когда приходит новое соединение или когда он читает сетевые сообщения. Ниже приведен код для реализации описанного выше сценария через BIO.
服务端代码BioServer.java
/**
* @author liujinkun
* @Title: BioServer
* @Description: BIO 服务端
* @date 2019/11/24 2:54 PM
*/
public class BioServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
while(true){
// accept()方法是个阻塞方法,如果没有客户端来连接,线程就会一直阻塞在这儿
Socket accept = serverSocket.accept();
InputStream inputStream = accept.getInputStream();
byte[] bytes = new byte[1024];
int len;
// read()方法是一个阻塞方法,当没有数据可读时,线程会一直阻塞在read()方法上
while((len = inputStream.read(bytes)) != -1){
System.out.println(new String(bytes,0,len));
}
}
}
}
В коде на стороне сервера создается сокет ServerSocket и привязывается к порту 8080, а затем в бесконечном цикле while вызывается метод accept() ServerSocket, позволяющий ему постоянно получать клиентские подключения. Метод accept() является методом блокировки, когда нет клиента для подключения, основной поток всегда будет заблокирован на методе accept() (явление: программа остановлена на строке метода accept() и не будет казнен). При наличии клиентского соединения основной поток разблокируется, и программа продолжает работать. Затем вызовите метод read() для чтения данных от клиента.Метод read() также является блокирующим методом.Если клиент отправляет данные, read() может прочитать данные, если нет данных для чтения, то основной поток снова останется в строке метода read().
Здесь используются два цикла while: внешний цикл while обеспечивает непрерывный прием соединения, а внутренний цикл while обеспечивает непрерывное чтение данных от клиента.
客户端代码BioClient.java
/**
* @author liujinkun
* @Title: BioClient
* @Description: BIO 客户端
* @date 2019/11/24 2:54 PM
*/
public class BioClient {
public static ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1",8080);
// 采用具有定时执行任务的线程池,来模拟客户端每隔一段时间来向服务端发送消息
// 这里是每隔3秒钟向服务端发送一条消息
executorService.scheduleAtFixedRate(()->{
try {
OutputStream outputStream = socket.getOutputStream();
// 向服务端发送消息(消息内容为:客户端的ip+端口+Hello World,示例:/127.0.0.1:999999 Hello World)
String message = socket.getLocalSocketAddress().toString() + " Hello World";
outputStream.write(message.getBytes());
outputStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
},0,3,TimeUnit.SECONDS);
}
}
В клиентском коде создается сокет Socket и указываются адрес сервера и номер порта для подключения. Затем, используя пул потоков с функцией регулярного выполнения задач, пусть клиент отправляет часть данных на сервер каждые 3 секунды.
Здесь для отправки данных каждые 3 секунды используется пул потоков с функцией выполнения задачи по времени, либо не обязательно использовать метод sleep() потока для имитации 3 секунд. Если у вас есть друзья, которые недостаточно осведомлены о пулах потоков, вы можете обратиться к этим двум статьям:Принцип реализации пула потоков ThreadPoolExecutorа такжеПочему запрещено использовать Исполнители для создания пулов потоков в «Руководстве по разработке Java для Alibaba»
Затем запускаем сервер и клиент соответственно, как видно из консоли сервера, строка будет печататься каждые 3 секунды客户端的ip+端口+Hello World
журнал.
/127.0.0.1:99999 Hello World
/127.0.0.1:99999 Hello World
/127.0.0.1:99999 Hello World
Чтобы имитировать доступ нескольких клиентов, мы запускаем еще один клиент, в это время мы ожидаем, что консоль сервера распечатает данные двух клиентов.ip+端口+Hello World
, поскольку сервер и два клиента находятся на одной машине, распечатанные в это время IP-адреса двух клиентов одинаковы, но порты должны быть разными. Ожидаемый вывод журнала должен быть примерно таким.
/127.0.0.1:99999 Hello World
/127.0.0.1:88888 Hello World
/127.0.0.1:99999 Hello World
/127.0.0.1:88888 Hello World
Однако это только то, что мы ожидаем, на самом деле это не так, когда мы запускаем другой клиент, мы обнаруживаем, что консоль всегда имеет только один номер клиентского порта, а не два.
Так почему? Причина в том, что в коде сервера метод read() является блокирующим, после подключения первого клиента считываются данные первого клиента, так как первый клиент никогда не разрывает соединение, сервер не отключается. не знаю, есть ли у него еще данные для отправки. В это время основной поток сервера ожидает в методе read(). Когда второй клиент обращается, основной поток блокируется в методе read(). , поэтому он не может выполнить метод accept() для обработки нового соединения, поэтому в настоящее время мы видим, что печатается только одно сообщение, отправленное клиентом.
так что нам делать? Теперь, когда мы знаем, что возникает проблема, основной поток блокируется в методе read(), то есть блокируется при чтении данных. Для решения проблемы блокировки наиболее прямым способом является использование технологии многопоточности, поэтому мы запускаем новый поток для чтения данных при чтении данных. Код сервера после обновления выглядит следующим образом.
服务端代码BioServerV2.java
/**
* @author liujinkun
* @Title: BioServer
* @Description: BIO 服务端
* @date 2019/11/24 2:54 PM
*/
public class BioServerV2 {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(8080);
while (true) {
// accept()方法是个阻塞方法,如果没有客户端来连接,线程就会一直阻塞在这儿
Socket accept = serverSocket.accept();
// 用另外一个线程来读写数据
handleMessage(accept);
}
}
private static void handleMessage(Socket socket) {
// 新创建一个线程来读取数据
new Thread(() -> {
try {
InputStream inputStream = socket.getInputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = inputStream.read(bytes)) != -1) {
System.out.println(new String(bytes, 0, len));
}
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
}
Код клиента остается неизменным, а BioClient по-прежнему используется. В серверном коде BioServerV2 операция чтения данных вынесена в метод handleMessage() для обработки, в этом методе будет создан новый поток для чтения данных, так что основной поток не будет заблокирован в метод read(). Запустите сервер и два клиента для проверки. Результат печати консоли выглядит следующим образом.
/127.0.0.1:99999 Hello World
/127.0.0.1:88888 Hello World
/127.0.0.1:99999 Hello World
/127.0.0.1:88888 Hello World
Хотя это решает проблему одновременного доступа нескольких клиентов, легко найти недостатки: всякий раз, когда новый клиент подключается к серверу, нам нужно создать поток для этого клиента для обработки чтения. Для операций с данными, когда параллелизм высока, нам нужно создавать много потоков, что явно нежелательно. Потоки являются ценным ресурсом сервера, и их создание и уничтожение занимает много времени, а когда потоков слишком много, процессор будет чаще переключаться между файлами в режиме онлайн, что приведет к медленному отклику службы. Когда потоков слишком много, могут даже возникать исключения, такие как переполнение дескриптора и OOM, что в конечном итоге приводит к простою службы. Кроме того, когда мы читаем данные, мы читаем данные на основе потоков ввода-вывода и можем читать только один или несколько байтов за раз, что имеет низкую производительность.
Поэтому серверная часть BIO подходит для сценариев приложений с низким параллелизмом, но для сценариев с высоким параллелизмом и большой нагрузкой на сервис использование BIO явно не подходит.
NIO
Чтобы решить проблему, что BIO не справляется с высоким параллелизмом, JDK, начиная с 1.4, предоставляет новый сетевой IO, а именно NIO, который обычно называют неблокирующим IO. Однако код NIO чрезвычайно сложен и труден для понимания.Нижеследующее кратко знакомит с соответствующими классами для написания NIO.
Классы, связанные с NIO, находятся вjava.nio
под пакет. В соответствии с ServerSocket и Socket в BIO, ServerSocketChannel и SocketChannel предоставляются в NIO для представления канала сервера и канала клиента соответственно. В отличие от BIO, концепция опросника Selector появляется в NIO, и разные операционные системы имеют разные методы реализации (базовая реализация платформы Windows — select, реализация epoll используется в ядре linux, а реализация poll используется в MacOS). . ). Кроме того, NIO основан на ByteBuffer для чтения и записи данных.
Представлено так много классов о NIO, что, по оценкам, вы тоже запутались, давайте посмотрим, как использовать NIO для достижения описанного выше сценария.
服务端代码NioServer.java
/**
* @author liujinkun
* @Title: NioServer
* @Description: NIO 服务端
* @date 2019/11/24 2:55 PM
*/
public class NioServer {
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 轮询器,不同的操作系统对应不同的实现类
Selector selector = Selector.open();
// 绑定端口
serverSocketChannel.bind(new InetSocketAddress(8080));
serverSocketChannel.configureBlocking(false);
// 将服务端channel注册到轮询器上,并告诉轮询器,自己感兴趣的事件是ACCEPT事件
serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);
while(true){
// 调用轮询器的select()方法,是让轮询器从操作系统上获取所有的事件(例如:新客户端的接入、数据的写入、数据的写出等事件)
selector.select(200);
// 调用select()方法后,轮询器将查询到的事件全部放入到了selectedKeys中
Set<SelectionKey> selectionKeys = selector.selectedKeys();
// 遍历所有事件
Iterator<SelectionKey> iterator = selectionKeys.iterator();
while(iterator.hasNext()){
SelectionKey key = iterator.next();
// 如果是新连接接入
if(key.isAcceptable()){
SocketChannel socketChannel = serverSocketChannel.accept();
System.out.println("有新客户端来连接");
socketChannel.configureBlocking(false);
// 有新的客户端接入后,就样将客户端对应的channel所感兴趣的时间是可读事件
socketChannel.register(selector,SelectionKey.OP_READ);
}
// 如果是可读事件
if(key.isReadable()){
// 从channel中读取数据
SocketChannel channel = (SocketChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
channel.read(byteBuffer);
byteBuffer.flip();
System.out.println(Charset.defaultCharset().decode(byteBuffer));
// 读完了以后,再次将channel所感兴趣的时间设置为读事件,方便下次继续读。当如果后面要想往客户端写数据,那就注册写时间:SelectionKey.OP_WRITE
channel.register(selector,SelectionKey.OP_READ);
}
// 将SelectionKey从集合中移除,
// 这一步很重要,如果不移除,那么下次调用selectKeys()方法时,又会遍历到该SelectionKey,这就造成重复处理了,而且最终selectionKeys这个集合的大小会越来越大。
iterator.remove();
}
}
}
}
Прочитав реализацию кода, вы можете еще больше запутаться. Такой простой Hello World должен написать так много кода и не может понять его весь. (Когда я впервые столкнулся с этими кодами и API, я думал, что не хочу узнавать ничего, связанного с NIO, во втором и третьем кварталах). Ниже приведено краткое объяснение этого кода.
-
- сначала через
ServerSocketChannel.open()
Эта строка кода создает канал на стороне сервера, который является сокетом на стороне сервера. (В 7-уровневой модели компьютерной сети или модели TCP/IP приложение верхнего уровня взаимодействует с нижним уровнем через сокет)
- сначала через
-
- пройти через
Selector.open()
Создается опросчик, который впоследствии используется для проверки того, какие сокеты готовы из операционной системы. Немного абстрактно так говорить, например. При посадке на поезд обычно есть ссылка на дополнительный билет. После каждой остановки в вагоне будет орать стюардесса Кому нужно оформлять билет? Тем, кому необходимо оформить билет, следует обратиться в номер вагона для его оформления. Эта стюардесса соответствует поллеру в НИО, и регулярно выходит в машину, чтобы прокричать голосом (то есть зайти в операционную систему, чтобы "зареветь голосом").В это время, если кому-то нужно составить билет( есть новый клиентский доступ или происходит событие чтения и записи)), то он попадет в соответствующую каретку (эти события доступа или события чтения и записи попадут в коллекцию selectKeys). Для БИО для каждого нового клиента нужно создавать новый поток, то есть каждый раз при появлении пассажира мы должны предоставить ему бортпроводника, что явно неразумно, а бортпроводников столько не может быть . Так что это огромное преимущество NIO перед BIO.
- пройти через
-
- Затем привяжите номер порта к серверу и установите его в неблокирующий режим. Целью использования NIO является использование его неблокирующих функций, поэтому здесь нам нужно вызвать
serverSocketChannel.configureBlocking(false)
установить неблокирующий
- Затем привяжите номер порта к серверу и установите его в неблокирующий режим. Целью использования NIO является использование его неблокирующих функций, поэтому здесь нам нужно вызвать
-
- Затем зарегистрируйте ServerSocketChannel в селекторе опросчика и сообщите опросчику, что интересующее его событие — это событие ACCEPT (канал на стороне сервера используется для обработки клиентского доступа, поэтому интересующее его событие — это событие ACCEPT. Почему ?Как насчет регистрации в поллере?Как было сказано ранее,поллер будет периодически заходить в операционную систему "реветь,кто хочет списать билет".Если он не зарегистрируется в поллере(не в поезде), Когда следователь рычит, как это можно услышать?)
-
- Затем, в цикле while, время от времени позволяйте опросчику обращаться к операционной системе, чтобы узнать, какие события произошли. Метод select() идет в операционную систему на опрос (рев), он может передавать параметр, указывающий, сколько миллисекунд ждать в операционной системе, если за это время не произойдет ни одного события (никто не хочет наверстать упущенное). билет), затем Возврат из операционной системы. Если происходит событие, поместите эти методы события в опросчик.
publicSelectedKeys
свойства, при вызовеselector.selectedKeys()
метод, эти события возвращаются.
- Затем, в цикле while, время от времени позволяйте опросчику обращаться к операционной системе, чтобы узнать, какие события произошли. Метод select() идет в операционную систему на опрос (рев), он может передавать параметр, указывающий, сколько миллисекунд ждать в операционной системе, если за это время не произойдет ни одного события (никто не хочет наверстать упущенное). билет), затем Возврат из операционной системы. Если происходит событие, поместите эти методы события в опросчик.
-
- Следующим шагом является определение типа события, следует ли получить событие, прочитать событие или записать событие, а затем выполнить различную обработку для каждого отдельного события.
-
- Наконец, удалите ключ из набора. См. комментарии к коду, почему он был удален. Ну, после стольких объяснений, в нем все еще много деталей, я думаю, вы все еще в замешательстве. Правильно, это характеристика NIO в JDK, операция громоздкая, включает множество классов и API, разработчикам очень сложно их освоить. Ключ в том, чтобы освоить его, не обязательно хорошо написанный код; хорошо написанный, не обязательно меньше ошибок; меньше ошибок, не обязательно высокая производительность. Метод записи JDK NIO подвержен ошибкам, если вы не будете осторожны. Вышеупомянутый метод записи NIO на стороне сервера.В настоящее время вы можете напрямую использовать клиент BIO для тестирования. Конечно, в NIO также есть метод написания на стороне клиента. Хотя метод написания NIO очень сложен, как только он родился, он снова знаком, и он привык к нему, увидев его несколько раз, поэтому метод написания клиента NIO опубликован ниже.
NIO客户端NioClient.java
/**
* @author liujinkun
* @Title: NioClient
* @Description: NIO客户端
* @date 2019/11/24 2:55 PM
*/
public class NioClient {
private static ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
public static void main(String[] args) throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
boolean connect = socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
// 因为连接是一个异步操作,所以需要在下面一行判断连接有没有完成。如果连接还没有完成,就进行后面的操作,会出现异常
if(!connect){
// 如果连接未完成,就等待连接完成
socketChannel.finishConnect();
}
// 每个3秒向服务端发送一条消息
executorService.scheduleAtFixedRate(() -> {
try {
String message = socketChannel.getLocalAddress().toString() + " Hello World";
// 使用ByteBuffer进行数据发送
ByteBuffer byteBuffer = ByteBuffer.wrap(message.getBytes());
socketChannel.write(byteBuffer);
} catch (IOException e) {
e.printStackTrace();
}
}, 0, 3, TimeUnit.SECONDS);
}
}
Метод написания клиента NIO относительно прост: он использует SocketChannel для привязки IP и порта, а затем вызывает метод connect() для подключения к серверу. Наконец, используйте ByteBuffer для загрузки данных и записи данных через SocketChannel.
По сравнению с BIO, NIO не нужно создавать поток для каждого соединения, он периодически получает готовые события от операционной системы через поллер, а затем обрабатывает их пакетами. В то же время NIO использует ByteBuffer для чтения и записи данных.По сравнению с BIO эффективность NIO выше, чем у одного байта или нескольких байтов данных через поток. Однако дизайн структуры данных ByteBuffer немного античеловеческий, и если вы не будете осторожны, будут ошибки. Что касается подробного описания работы API ByteBuffer, заинтересованные друзья могут попробовать написать его самостоятельно. Разницу между BIO и NIO можно представить на следующем рисунке.
Netty
BIO не подходит для использования в условиях высокого параллелизма, и хотя NIO может справиться с сценариями высокого параллелизма, с одной стороны, он сложен в написании и освоении, а главное, есть баги в пустом опросе (причина пустого опрос — это ради ОС), поэтому появилась Нетти. В настоящее время Netty является наиболее широко используемой сетевой структурой, официально говоря: это высокопроизводительная сетевая среда, управляемая событиями. На самом деле, это фреймворк, обертывающий NIO, и он позволяет избежать ошибки обучения полого вращения JDK. Хотя это оболочка вокруг NIO, она оптимизирует многие операции для повышения производительности. В настоящее время во многих популярных средах Java Netty используется на нижнем уровне для сетевого взаимодействия, например, Dubbo, Motan, асинхронное программирование Spring5 в среде RPC, очередь сообщений RocketMQ и т. д. — все они используют Netty для сетевого взаимодействия.
Поскольку Netty так хороша, как ее использовать? Затем используйте Netty для реализации описанного выше сценария.服务端NettyServer.java
/**
* @author liujinkun
* @Title: NettyServer
* @Description: Netty服务端
* @date 2019/11/24 2:56 PM
*/
public class NettyServer {
public static void main(String[] args) {
// 负责处理连接的线程组
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
// 负责处理IO和业务逻辑的线程组
NioEventLoopGroup workerGroup = new NioEventLoopGroup(8);
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
// 添加日志打印,用来观察Netty的启动日志
.handler(new LoggingHandler(LogLevel.INFO))
// 添加用来处理客户端channel的处理器handler
.childHandler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
ChannelPipeline pipeline = nioSocketChannel.pipeline();
// 字符串解码器
pipeline.addLast(new StringDecoder())
// 自定义的handler,用来打印接收到的消息
.addLast(new SimpleChannelInboundHandler<String>() {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, String message) throws Exception {
System.out.println(message);
}
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
super.channelRegistered(ctx);
System.out.println("有新客户端连接");
}
});
}
});
// 绑定端口,并启动
ChannelFuture channelFuture = serverBootstrap.bind(8080).sync();
channelFuture.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
// 关闭线程组
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
Хотя приведенный выше код выглядит очень длинным, этот код почти не изменился, он применим почти ко всем сценариям, нам нужно только изменить соответствующие методы строки childHandler(). Код здесь предназначен для обработки нашей пользовательской бизнес-логики. Конкретные детали кода подробно объяснять не буду, позже я напишу отдельную статью, чтобы разобрать запуск сервера Netty, доступ к новым соединениям, обработку данных и распаковку полупакетов из интерпретации исходный код.
Запустите NettyServer, вы можете напрямую использовать BioClient или NioClient для тестирования NettyServer. Конечно, у Netty также есть метод написания на стороне клиента. код показывает, как показано ниже.
Netty客户端NettyClient
/**
* @author liujinkun
* @Title: NettyClient
* @Description: Netty客户端
* @date 2019/11/24 2:57 PM
*/
public class NettyClient {
private static ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
public static void main(String[] args) {
// 客户端只需要一个线程组即可
NioEventLoopGroup nioEventLoopGroup = new NioEventLoopGroup();
try {
// 采用Bootstrap而不是ServerBootstrap
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(nioEventLoopGroup)
// 设置客户端的SocketChannel
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
ChannelPipeline pipeline = nioSocketChannel.pipeline();
// 添加一个字符串编码器
pipeline.addLast(new StringEncoder());
}
});
ChannelFuture channelFuture = bootstrap.connect("", 8080).sync();
Channel channel = channelFuture.channel();
executorService.scheduleAtFixedRate(()->{
String message = channel.localAddress().toString() + " Hello World";
channel.writeAndFlush(message);
},0,3,TimeUnit.SECONDS);
channel.closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
nioEventLoopGroup.shutdownGracefully();
}
}
}
На самом деле код клиента почти исправлен, этот код можно использовать повторно во всех сценариях, единственное, что нужно изменить, это метод handler(), нужно добавить разные обработчики для собственной бизнес-логики.
По сравнению с методом записи NIO, метод записи Netty более лаконичен, а объем кода относительно невелик.Несколько строк простого кода могут решить такие проблемы, как запуск службы, доступ к новому соединению, чтение и запись данных, кодирование и декодирование. Вот почему Netty так широко используется. По сравнению с NIO Netty имеет следующие преимущества.
-
- NIO JDK имеет ошибку пустого опроса, и Netty ловко избегает этого;
-
- API JDK сложен, и разработчикам сложно его использовать, что еще более важно, в нем легко писать ошибки, в то время как API Netty прост и удобен в использовании.
-
- У Netty более высокая производительность, сделано много оптимизаций производительности на основе JDK, например, селектор в
publicSelectedKeys
Структура данных свойства была изменена с коллекции Set на массив.
- У Netty более высокая производительность, сделано много оптимизаций производительности на основе JDK, например, селектор в
-
- Нижний уровень Netty может переключать модель ввода-вывода по желанию.Для трехпоточных моделей Reactor модель ввода-вывода можно переключить только путем изменения параметров.
-
- Netty была протестирована во многих сценариях с высокой степенью параллелизма, таких как проверка сред RPC, таких как Dubbo.
-
- Netty помогает нам решать такие проблемы, как склеивание и распаковка TCP, разработчикам не нужно заботиться об этих проблемах, им нужно сосредоточиться только на разработке бизнес-логики.
-
- Netty поддерживает множество стеков протоколов. Производительность сериализации объектов, которая поставляется с JDK, очень низкая, а поток кода после сериализации велик, но другие методы сериализации имеют более высокую производительность, например protobuf.
-
- Есть много преимуществ...
Суммировать
-
В этой статье сравниваются их преимущества и недостатки на примере сценария, от реализации BIO до реализации NIO и, наконец, до реализации Netty.Нет сомнений в том, что Netty является предпочтительной структурой для сетевого программирования, и существует множество их.
-
Наконец, чтобы подвести итог, обучение Netty сложно, и в нем задействовано много точек знаний и существительных. Вам нужно набраться терпения, тщательно обдумать и написать больше примеров кода. Автор просмотрел два набора видеороликов, «Авторитетное руководство по Netty» и все связанные с netty статьи, опубликованные в InfoQ Ли Линьфэном, автором «Авторитетного руководства по Netty», и даже узнал о сети в компьютерных сетях и операционных системах. Я, наконец, почувствовал, что только начинаю. Конечно, сравнивает блюда в основном автор.
-
Если вы хотите хорошо изучить Netty, рекомендуется взглянуть на API-интерфейсы, связанные с NIO, в JDK.Хотя эти API-интерфейсы очень сложны для написания, они будут очень полезны для изучения Netty. Тогда его трудно использовать, вы не можете использовать его, если выучите его, но вы не можете не выучить его.
-
Если у вас есть друг, которому нужно учебное пособие по Netty, вы можете подписаться на общедоступную учетную запись и связаться с автором, чтобы получить бесплатное видео.