Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >用Socket编程?我还是选择了Netty

用Socket编程?我还是选择了Netty

作者头像
架构师修炼
发布于 2021-05-17 08:25:31
发布于 2021-05-17 08:25:31
3.4K00
代码可运行
举报
文章被收录于专栏:架构师修炼架构师修炼
运行总次数:0
代码可运行

最近在写IO的这块的内容,于是就免不了去研究IO,NIO,AIO,在看NIO的时候,阿粉就发现了一个极其好的东西,那就是Netty,为什么说他好呢?大家就跟着阿粉来深度认识一下Netty吧。

什么是Netty

我们先看看百度百科给我们的解释,什么是Netty

百度百科:

Netty是由JBOSS提供的一个java开源框架,现为Github上的独立项目。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。

也就是说,Netty 是一个基于NIO的客户、服务器端的编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户、服务端应用。Netty相当于简化和流线化了网络应用的编程开发过程,例如:基于TCPUDP的socket服务开发。

上面是来自于百度百科给出的解释,我们也能清晰的看到,Netty是一个基于NIO的模型,使用Netty的地方很多就是socket服务开发,而关于NIO,相信大家肯定不陌生,因为之前阿粉出过一篇文章,也给NIO说的是明明白白。

文章连接奉上:

如果有人再问你 Java IO,把这篇文章砸他头上

对比Netty和传统的Socket

我们既然要说Netty,那么我们肯定要对Netty还有Socket不同的代码进行一个分析,分析的透彻了,你才能真的选择使用Netty,而不再进行Socket的开发了,相信到时候,大家肯定会做出最正确的选择。

传统Socket编程服务端
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

package com.example.demo.socket;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @ClassName SocketDemo
 * @Author yld
 * @Date 2021/4/19 10:33
 * @Description SocketDemo
 */
public class SocketServerDemo {

    public static void main(String[] args) {
        ServerSocket server=null;
        try {
            server=new ServerSocket(18080);
            System.out.println("时间服务已经启动--端口号为:18080...");
            while (true){
                Socket client = server.accept();
                //每次接收到一个新的客户端连接,启动一个新的线程来处理
                new Thread(new TimeServerHandler(client)).start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                server.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.demo.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Calendar;

/**
 * @ClassName TimeServerHandler
 * @Author yld
 * @Date 2021/4/19 10:35
 * @Description TimeServerHandler
 */
public class TimeServerHandler implements Runnable {
    private Socket clientProxxy;

    public TimeServerHandler(Socket clientProxxy) {
        this.clientProxxy = clientProxxy;
    }

    @Override
    public void run() {
        BufferedReader reader = null;
        PrintWriter writer = null;
        try {
            reader = new BufferedReader(new InputStreamReader(clientProxxy.getInputStream()));
            writer =new PrintWriter(clientProxxy.getOutputStream()) ;
            while (true) {//因为一个client可以发送多次请求,这里的每一次循环,相当于接收处理一次请求
                String request = reader.readLine();
                if (!"GET CURRENT TIME".equals(request)) {
                    writer.println("BAD_REQUEST");
                } else {
                    writer.println(Calendar.getInstance().getTime().toLocaleString());
                }
                writer.flush();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            try {
                writer.close();
                reader.close();
                clientProxxy.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
传统Socket编程客户端
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.demo.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * @ClassName SocketClientDemo
 * @Author yld
 * @Date 2021/4/19 10:42
 * @Description SocketClientDemo
 */
public class SocketClientDemo {
    public static void main(String[] args)  {
        BufferedReader reader = null;
        PrintWriter writer = null;
        Socket client=null;
        try {
            client=new Socket("127.0.0.1",18080);
            writer = new PrintWriter(client.getOutputStream());
            reader = new BufferedReader(new InputStreamReader(client.getInputStream()));

            while (true){//每隔5秒发送一次请求
                writer.println("GET CURRENT TIME");
                writer.flush();
                String response = reader.readLine();
                System.out.println("Current Time:"+response);
                Thread.sleep(5000);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                writer.close();
                reader.close();
                client.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

老生常谈,我们来执行一下才能知道效果,

首先运行服务端:

TimeServer Started on 18080...

接着启动客户端

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Current Time:2021-4-19 10:48:21
Current Time:2021-4-19 10:48:26
Current Time:2021-4-19 10:48:31
Current Time:2021-4-19 10:48:36
Current Time:2021-4-19 10:48:41
Current Time:2021-4-19 10:48:46
Current Time:2021-4-19 10:48:51

大家看一下,这是不是就是相当于一个Socket的客户端和服务端之间进行通信的过程,在client端可以发送请求指令"GET CURRENT TIME"给server端,每隔5秒钟发送一次,每次server端都返回当前时间。

而这也是传统的BIO的做法,每一个client都需要去对应一个线程去进行处理,client越多,那么你要开启的线程也就会越多,也就是说,如果采用BIO通信模型的服务端,通常由一个独立的Acceptor线程负责监听客户端的连接,当接收到客户端的连接请求后,会为每一个客户端请求创建新的线程进行请求的处理,处理完成后通过输出流返回信息给客户端,响应完成后销毁线程。

模型图如下

这时候就有大佬说,你不会用线程池么?但是阿粉之前曾经在面试的时候说过,使用线程池的话,它实际上并没有解决任何实际性的问题,他实际上就是对BIO做了一个优化,属于伪异步IO通信。

伪异步IO通信模型图

异步IO通信确实能缓解一部分的压力,但是这种模型也是有缺陷的,当有大量客户端请求的时候,随着并发访问量的增长,伪异步IO就会造成线程池阻塞。

这时候就取决于你们这个是想选择,系统发生线程堆栈溢出、创建新线程失败等问题呢,还是选择大量客户端请求,造成线程池阻塞。

都说,技术是为了解决问题而出现的,那么接下来就有了解决这个问题的技术出现了,Netty,我们来看看Netty吧。

Netty环境搭建

在这里我们使用的依旧是Springboot来整合Netty的环境,然后在后续过程中,使用Netty实现服务端程序和客户端程序,最后阿粉还会继续给大家再说一下这个BIO和NIO的模型,虽然Netty并没有实现传说中的AIO,但是已经算是吧这个NIO的模型,实现到了极致了。

来,既然使用Springboot,那我们就把项目搭建一下吧,顺便把我们的Netty依赖都加入进来。

(1).我们先创建出来一个项目

(2).加入我们的pom的依赖

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 <!--Netty-->
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-all</artifactId>
            <version>4.1.31.Final</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>

        <!-- logger -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.25</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>
        
Netty服务端程序
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package com.example.demo.netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * @ClassName NettyServerDemo
 * @Author yld
 * @Date 2021/4/19 11:11
 * @Description NettyServerDemo
 */
public class NettyServerDemo {

    private int port=18081;
    public void run() throws Exception {
        EventLoopGroup bossGroup = new NioEventLoopGroup(); 
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap(); 
            b.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class) 
                    .childHandler(new ChannelInitializer<SocketChannel>() { 
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
                            ch.pipeline().addLast(new StringDecoder());
                            ch.pipeline().addLast(new TimeServerHandler());
                        }
                    });

            ChannelFuture f = b.bind(port).sync(); 
            System.out.println("TimeServer Started on 18081...");
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }
    public static void main(String[] args) throws Exception {
        new NettyServerDemo().run();
    }
}

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

package com.example.demo.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.Date;

/**
 * @ClassName TimeServerHandler
 * @Author yld
 * @Date 2021/4/19 11:19
 * @Description TimeServerHandler
 */
public class TimeServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String request = (String) msg;
        String response = null;
        if ("QUERY TIME ORDER".equals(request)) {
            response = new Date(System.currentTimeMillis()).toString();
        } else {
            response = "BAD REQUEST";
        }
        response = response + System.getProperty("line.separator");
         ByteBuf resp = Unpooled.copiedBuffer(response.getBytes());
        ctx.writeAndFlush(resp);
    }
}

Netty客户端程序
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

package com.example.demo.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;

/**
 * @ClassName NettyClientDemo
 * @Author yld
 * @Date 2021/4/19 11:21
 * @Description NettyClientDemo
 */
public class NettyClientDemo {
    public static void main(String[] args) throws Exception {
        String host = "localhost";
        int port = 18081;
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(workerGroup);
            b.channel(NioSocketChannel.class);
            b.handler(new ChannelInitializer<SocketChannel>() {
                @Override
                public void initChannel(SocketChannel ch) throws Exception {
                    ch.pipeline().addLast(new LineBasedFrameDecoder(1024));
                    ch.pipeline().addLast(new StringDecoder());
                    ch.pipeline().addLast(new TimeClientHandler());
                }
            });
            // 开启客户端.
            ChannelFuture f = b.connect(host, port).sync();
            // 等到连接关闭.
            f.channel().closeFuture().sync();
        } finally {
            workerGroup.shutdownGracefully();
        }
    }
}

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

package com.example.demo.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

/**
 * @ClassName TimeClientHandler
 * @Author yld
 * @Date 2021/4/19 11:22
 * @Description TimeClientHandler
 */
public class TimeClientHandler extends ChannelInboundHandlerAdapter {

    private byte[] req=("QUERY TIME ORDER" + System.getProperty("line.separator")).getBytes();
    @Override
    public void channelActive(ChannelHandlerContext ctx) {//1
        ByteBuf message = Unpooled.buffer(req.length);
        message.writeBytes(req);
        ctx.writeAndFlush(message);
    }
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String body = (String) msg;
        System.out.println("Now is:" + body);
    }
}

首先启动服务端,控制台输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
TimeServer Started on 18081...

接着启动客户端,控制要输出:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Now is:Mon Apr 19 11:34:21 CST 2021

既然代码写了,那我们是不是就得来分析一下这个Netty在中间都干了什么东西,他的类是什么样子的,都有哪些方法。

大家先从代码的源码上开始看起,因为我们在代码中分别使用到了好几个类,而这些类的父类,或者是接口定义者追根到底,也就是这个样子的,我们从IDEA中打开他的类图可以清晰的看到。

而在源码中,最重要的就是这个Channel,接下来,我们就来分析一波吧。

Channel

相信大家对看源码这块绝对是觉得非常难受,阿粉也是,但是还是需要给大家进行分析源码,不然怎么知道源码创作者是什么意思呢?

All I/O operations are asynchronous.一句话点出核心所有的IO操作都是异步的,这意味着任何I/O调用都将立即返回,但不保证请求的I/O操作已完成。这是在源码的注释上面给出的解释。

Channel分类

  • 服务端: NioServerSocketChannel
  • 客户端: NioSocketChannel

看到这个,大家肯定也都不陌生,因为Channel即可以在JDK的Socket中充当管道出现,同时,也在Netty的服务端和客户端进行IO数据交互,充当一个媒介的存在,那么他的区别在哪?

Netty对Jdk原生的ServerSocketChannel进行了封装和增强封装成了NioXXXChannel, 相对于原生的JdkChannel,Netty的Channel增加了如下的组件。

  • id 标识唯一身份信息
  • 可能存在的parent Channel
  • 管道 pepiline
  • 用于数据读写的unsafe内部类
  • 关联上相伴终生的NioEventLoop

如果大家想对这个这个类的API有更多的了解,官网给大家送上。

Package io.netty.channel

今天这篇文章,我们先分析各种源代码,然后在接下来的文章,阿粉会给大家介绍关于Netty的线程模型,他使用的是什么线程模型来实现NIO的网络模型。

而关于Channel,其实换成大家容易理解的话的话,那就是由它负责同对端进行网络通信、注册和数据操作等功能

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
A Channel can have a parent depending on how it was created. For instance, a SocketChannel, that was accepted by ServerSocketChannel, will return the ServerSocketChannel as its parent on parent().

The semantics of the hierarchical structure depends on the transport implementation where the Channel belongs to. For example, you could write a new Channel implementation that creates the sub-channels that share one socket connection, as BEEP and SSH do.

一个Channel可以有一个父Channel,这取决于它是如何创建的。例如,被ServerSocketChannel接受的SocketChannel将返回ServerSocketChannel作为其parent()上的父对象。层次结构的语义取决于通道所属的传输实现。

Channel的抽象类AbstractChannel中有一个受保护的构造方法,而AbstractChannel内部有一个pipeline属性,Netty在对Channel进行初始化的时候将该属性初始化为DefaultChannelPipeline的实例。

为什么选择Netty

其实在上面的图中,已经能看出来了,不同的I/O模型,效率,使用难度,吞吐量都是非常重要的,所以选择的时候,肯定要慎重选择,而我们为什么不使用Java原生的呢?

实际上很简单,1.复杂,2.不好用

对于Java的NIO的类库和API繁杂使用麻烦,你需要熟练掌握Selectol,ServerSocketChannel,SocketChannel,ByteBuffer 等

JDK NIO的BUG,比如epoll bug,这个BUG会在linux上导致cpu 100%,使得nio server/client不可用,而且在1.7中都没有解决完这个bug,只不过发生频率比较低。

而Netty是一个高性能、异步事件驱动的NIO框架,它提供了对TCP、UDP和文件传输的支持,作为一个异步NIO框架,Netty的所有IO操作都是异步非阻塞的,通过Future-Listener机制,用户可以方便的主动获取或者通过通知机制获得IO操作结果。

所以,综上考虑,我们还是选择使用了Netty,而不使用Socket,作为开发者的你,会选择什么样的I/O模型呢?

文章参考

《Netty实战》

《田守枝的Java技术博客》

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 架构师修炼 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Netty服务端与客户端(源码一)
  (4)创建Selector,将之前创建的ServerSocketChannel注册到Selector上,监听SelectionKeyACCEPT。
用户3003813
2018/09/06
1.6K0
Netty服务端与客户端(源码一)
Netty入门_合并财务报表应用指南
一个简单的NIO服务端程序,如果我们直接使用JDK的NIO类库进行开发,竟然需要经过繁琐的十多步操作才能完成最基本的消息读取和发送,这也是我们选择Netty框架的原因了。下面我们看看Netty是如何轻松搞定服务端开发的。
全栈程序员站长
2022/11/09
3540
Netty 之入门应用
系列文章:http://www.jianshu.com/p/594441fb9c9e
Yano_nankai
2018/10/08
4360
Netty的TCP粘包/拆包(源码二)
假设客户端分别发送了两个数据包D1和D2给服务器,由于服务器端一次读取到的字节数是不确定的,所以可能发生四种情况:
用户3003813
2018/09/06
9030
Netty的TCP粘包/拆包(源码二)
Socket粘包问题终极解决方案—Netty版(2W字)!
上一篇我们讲了《Socket粘包问题的3种解决方案》,但没想到评论区竟然炸了。介于大家的热情讨论,以及不同的反馈意见,本文就来做一个扩展和延伸,试图找到问题的最优解,以及消息通讯的最优解决方案。
磊哥
2021/01/14
5980
Socket粘包问题终极解决方案—Netty版(2W字)!
Netty | 属于你的第一款Netty应用程序
我在这里偷懒了,直接是导入了netty-all,如果不想的话,大家可以用到什么导入什么,因为Netty支持的特别广,所以有不同的Jar包。
宁在春
2022/10/31
3200
Netty | 属于你的第一款Netty应用程序
Spring Boot 与 Netty 的概念与实战
Spring Boot: Spring Boot 是一个基于 Spring 框架的开发框架,旨在简化 Spring 应用的开发。它提供了一系列的默认配置和开发工具,帮助开发者快速构建和部署 Spring 应用。
小马哥学JAVA
2024/07/03
2890
Java IO,NIO以及Netty网络编程
同步阻塞I/O模式:当一条线程执行 read() 或者 write() 方法时,这条线程会一直阻塞直到读取一些数据或者写出去的数据已经全部写出,在这期间这条线程不能做任何其他的事情。在活动连接数不是特别高(小于单机1000)的情况下,这种模型是比较不错的,可以让每一个连接专注于自己的 I/O 并且编程模型简单,也不用过多考虑系统的过载、限流等问题。
AnieaLanie
2021/12/11
7760
Netty(一)之helloworld
客户端通向服务器端发送消息,服务器端读取数据(你好)并且返回(new Date()),客户端读取数据
CBeann
2023/12/25
1540
史诗级最强教科书式“NIO与Netty编程”
java.nio全称java non-blocking IO,是指JDK1.4开始提供的新API。从JDK1.4开始,Java提供了一系列改进的输入/输出的新特性,也被称为NIO(既New IO),新增了许多用于处理输入输出的类,这些类都被放在java.nio包及子包下,并且对原java.io包中的很多类进行改写,新增类满足NIO的功能。 NIO和BIO有着相同的目的和作用,但是它们的实现方式完全不同,BIO以流的方式处理数据,而NIO以块的方式处理数据,块I/O的效率比流I/O高很多。另外,NIO是非阻塞式的,这一点跟BIO也很不相同,使用它可以提供非阻塞式的高伸缩性网络。 NIO主要有三大核心部分 :Channel(通道),Buffer(缓冲区),Selector(选择器)。传统的BIO基于字节流和字符流进行操作,而NIO基于Channel和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择区)用于监听多个通道的事件(比如 :连接打开,数据到达)。因此使用单个线程就可以监听多个数据管道。
海仔
2019/08/26
9390
史诗级最强教科书式“NIO与Netty编程”
Netty 线程模型与基本使用
Netty 是一个异步事件驱动的网络应用程序框架,用于快速开发可维护的高性能和高伸缩性的服务器和客户端。Netty 拥有高性能,吞吐量更高,延迟更低,减少资源消耗,最小化不必要的内存复制等优点。
Se7en258
2021/05/18
1.1K0
Netty 线程模型与基本使用
netty 入门
我们一般会用Http客户端库来调用web服务,获取数据。如果一个东西是出于一般性目的设计出来的,那么他在某些方面可能就不是最合适的。比如获取大文件,收发邮件,展示实时的金融数据,游戏数据传输等。为了实现这些需求,需要一个为其高度优化的特定协议。还有一个无法避免的问题是你可能需要调用老系统的数据,但是他的协议又是特定。重点来了,如何在不牺牲可靠性和性能的前提下快速实现这么一个系统。
_淡定_
2020/05/12
7760
Netty(二)之整合Marshalling传输实体类
Netty之传输POJO(使用JBoss的Marshalling序列化方式)_Learning-CSDN博客_marshalling netty
CBeann
2023/12/25
1420
Netty[Netty从入门到精通]
应用层:Http协议、电子文件传输、文件服务器等 表示层:解决我们不同系统之间语法的通讯 会话层:建立与应用程序之间的通讯 传输层:提供了端口号和接口协议TPC/UDP
高大北
2022/09/02
1.1K0
Netty[Netty从入门到精通]
java架构之路-(netty专题)netty的基本使用和netty聊天室
  上次博客,我们主要说了我们的IO模型,BIO同步阻塞,NIO同步非阻塞,AIO基于NIO二次封装的异步非阻塞,最重要的就是我们的NIO,脑海中应该有NIO的模型图。
小菜的不能再菜
2020/02/23
1.3K0
Netty教程系列(一)——netty入门应答程序
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
逝兮诚
2019/10/30
6810
Netty教程系列(一)——netty入门应答程序
Netty入门HelloWorld
今天下班之后无聊,学习了一下长链接的一款非常秀的框架——netty,netty在很多?️java开发的中间件中都有很坚实的地位。于是,在下班之余我学习了一下这款优秀的框架。 从开始搭建到运行 需要准备
简单的程序员
2020/04/20
5610
Netty入门HelloWorld
【Netty】NIO编程的利器
今天换换口味,由于本人工作中马上要用到Netty这个东西,所以这几天也是开始学习,此学习过程应该会是一个完整的系列,初步的目标是先会用,之后有机会再深入。鉴于笔者之前也从未使用过Netty,所以有什么疏漏错误的,希望大家指正,先行感谢!
周三不加班
2019/09/04
4110
【Netty】NIO编程的利器
netty 之 telnet HelloWorld 详解
Netty是 一个异步事件驱动的网络应用程序框架, 用于快速开发可维护的高性能协议服务器和客户端。
sanshengshui
2019/09/11
8990
netty 之 telnet HelloWorld 详解
Netty之旅二:口口相传的高性能Netty到底是什么?
高清思维导图原件(xmind/pdf/jpg)可以关注公众号:一枝花算不算浪漫 回复netty01即可。
一枝花算不算浪漫
2020/08/25
7970
Netty之旅二:口口相传的高性能Netty到底是什么?
相关推荐
Netty服务端与客户端(源码一)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验