0%

java | 分工细化

相对于 java | IO 任务 进行细化。

客户端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.redisc;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;

import java.io.IOException;
import java.net.InetSocketAddress;

public class Client {
public static void main(String[] args) throws IOException, InterruptedException {
Channel channel = new Bootstrap()
.group(new NioEventLoopGroup())
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<NioSocketChannel>() {
@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline().addLast(new StringEncoder());

}
}).connect(new InetSocketAddress("localhost", 8000))
.sync().channel();
channel.writeAndFlush("hello");
}
}

26 处打断点。

服务端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package com.redisc;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.charset.Charset;

import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.Logger;


@Slf4j
public class Run {

public static void main(String[] args) throws IOException {
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger rootLogger = loggerContext.getLogger("io.netty");
rootLogger.setLevel(ch.qos.logback.classic.Level.OFF);

new ServerBootstrap()
// group 的两个参数
// boss 和 worker
// boss 只负责 ServerSocketChannel 上 accept 事件
// worker 只负责 socketChannel 上读写
// 请参考 https://benpaodewoniu.github.io/2023/01/08/java184/
.group(new NioEventLoopGroup(), new NioEventLoopGroup(2))
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {

@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline().addLast(new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buffer = (ByteBuf) msg;
log.debug(buffer.toString(Charset.defaultCharset()));
}
});
}

}).bind(8000);
}

}
  • 开启服务器
  • 开启客户端
    • 到断点处,自己发送信息
    • 一共开启 3 个独立的客户端「客户端不关闭」
    • 重复发送

服务端输出

1
2
3
23:16:22.960 [nioEventLoopGroup-3-1] DEBUG com.redisc.Run - hello
23:23:36.518 [nioEventLoopGroup-3-2] DEBUG com.redisc.Run - 123
23:24:04.125 [nioEventLoopGroup-3-1] DEBUG com.redisc.Run - 222

因为,worker 线程只有两个,所以,是两个线程分别处理。

但是,这个方式有一个缺陷,就是,当某一个任务处理时常非常长的时候,其他的任务得不到处理。

优化服务器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.redisc;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.nio.charset.Charset;

import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.Logger;


@Slf4j
public class Run {

public static void main(String[] args) throws IOException {
LoggerContext loggerContext = (LoggerContext) LoggerFactory.getILoggerFactory();
Logger rootLogger = loggerContext.getLogger("io.netty");
rootLogger.setLevel(ch.qos.logback.classic.Level.OFF);

EventLoopGroup eventLoopGroup = new DefaultEventLoopGroup();

new ServerBootstrap()
// group 的两个参数
// boss 和 worker
// boss 只负责 ServerSocketChannel 上 accept 事件
// worker 只负责 socketChannel 上读写
// 请参考 https://benpaodewoniu.github.io/2023/01/08/java184/
.group(new NioEventLoopGroup(), new NioEventLoopGroup(2))
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<NioSocketChannel>() {

@Override
protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception {
nioSocketChannel.pipeline().addLast("handler1",new ChannelInboundHandlerAdapter() {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buffer = (ByteBuf) msg;
log.debug(buffer.toString(Charset.defaultCharset()));
ctx.fireChannelRead(msg); // 必须加上这句话才能传递给下一个 pipline
}
}).addLast(eventLoopGroup,"handler2",new ChannelInboundHandlerAdapter(){
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
ByteBuf buffer = (ByteBuf) msg;
log.debug(buffer.toString(Charset.defaultCharset()));
}
});
}

}).bind(8000);
}

}

这里又弄了一个 EventLoopGroup,并添加到了 pipeline 中,可以专门用来处理耗时时间长的操作。

开启一个客户端,输出如下

1
2
23:45:19.310 [nioEventLoopGroup-4-1] DEBUG com.redisc.Run - hello
23:45:19.318 [defaultEventLoopGroup-2-1] DEBUG com.redisc.Run - hello
请我喝杯咖啡吧~