一、Socket编程
1. 通过Socket编程可以和其他机器通信,监听本机某个端口号,收取其他机器发到本机上这个端口号上的消息,基于TCP协议,操作系统只认TCP协议
2. 三种操作:Accept连接操作、读操作、写操作,Socket编程需要在连接成功后,启动一个while死循环的线程进行读写操作
3. 可以定制编码解码协议,实现自己特定协议的服务器,例如HTTP服务器、Redis服务器、WebSocket服务器、FTP服务器、UDP服务器、RPC服务器、MySQL的Proxy服务器等
二、NIO
1. Socket编程属于BIO,即Blocking IO,阻塞IO,连接/读/写都是阻塞的
2. NIO可以IO多路复用,通过事件机制使多个线程非阻塞
三、Reactor线程模型
1. 单线程模型:一个NIO+一个accept线程
2. 多线程模型:使用了线程池
3. 主从模型:
四、Netty
1. Java的NIO使用不方便,并且有bug(epoll空轮询使CPU使用率100%),强烈不建议使用原生NIO
2. Netty是对NIO的进一步封装,通过Reactor线程模型对连接/读/写进行处理
五、TCP粘包/拆包:
1. 底层发送的都是字节流,而发送的时候需要使用应用层的协议粘包,粘包有固定的长度,接收到固定长度的数据后使用应用层的协议拆包
2. Netty已经有很多类型的拆包器
六、Netty的零拷贝
1. 发送数据的时候,需要把数据从磁盘上拷贝到内存中,从网卡发送出去
2. 传统的数据拷贝:4次拷贝和上下文切换
3. Netty的数据拷贝:FileChannel.transferTo()方法,减少到2次拷贝,并不需要CPU参与,即零拷贝
七、Netty的使用
1. 依赖的jar包
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> <version>4.1.6.Final</version> </dependency>
2. 服务器端监听端口号并读取数据
public class NettyServer { public static void main(String[] args) { ServerBootstrap serverBootstrap = new ServerBootstrap(); NioEventLoopGroup boos = new NioEventLoopGroup(); NioEventLoopGroup worker = new NioEventLoopGroup(); serverBootstrap .group(boos, worker) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<NioSocketChannel>() { protected void initChannel(NioSocketChannel ch) { ch.pipeline().addLast(new StringDecoder()); ch.pipeline().addLast(new SimpleChannelInboundHandler<String>() { @Override protected void channelRead0(ChannelHandlerContext ctx, String msg) { System.out.println(msg); } }); } }) .bind(8000); } }
3. 客户端发送数据
public class NettyClient { public static void main(String[] args) throws InterruptedException { Bootstrap bootstrap = new Bootstrap(); NioEventLoopGroup group = new NioEventLoopGroup(); bootstrap.group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel ch) { ch.pipeline().addLast(new StringEncoder()); } }); Channel channel = bootstrap.connect("127.0.0.1", 8000).channel(); while (true) { channel.writeAndFlush(new Date() + ": hello world!"); Thread.sleep(2000); } } }
参考:
https://segmentfault.com/a/1190000017128263?utm_source=tag-newest