1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.mina.core.nio.udp;
21
22 import io.netty.bootstrap.Bootstrap;
23 import io.netty.bootstrap.ServerBootstrap;
24 import io.netty.buffer.ByteBuf;
25 import io.netty.buffer.Unpooled;
26 import io.netty.channel.ChannelHandlerContext;
27 import io.netty.channel.ChannelInitializer;
28 import io.netty.channel.ChannelOption;
29 import io.netty.channel.SimpleChannelInboundHandler;
30 import io.netty.channel.nio.NioEventLoopGroup;
31 import io.netty.channel.socket.DatagramChannel;
32 import io.netty.channel.socket.DatagramPacket;
33 import io.netty.channel.socket.nio.NioDatagramChannel;
34 import io.netty.util.Attribute;
35 import io.netty.util.AttributeKey;
36
37 import java.io.IOException;
38 import org.apache.mina.core.BenchmarkServer;
39
40
41
42
43
44
45 public class Netty4UdpBenchmarkServer implements BenchmarkServer {
46
47 private static enum State {
48 WAIT_FOR_FIRST_BYTE_LENGTH, WAIT_FOR_SECOND_BYTE_LENGTH, WAIT_FOR_THIRD_BYTE_LENGTH, WAIT_FOR_FOURTH_BYTE_LENGTH, READING
49 }
50
51 private static final ByteBuf ACK = Unpooled.buffer(1);
52
53 private static final AttributeKey<State> STATE_ATTRIBUTE = new AttributeKey<State>("state");
54
55 private static final AttributeKey<Integer> LENGTH_ATTRIBUTE = new AttributeKey<Integer>("length");
56
57 static {
58 ACK.writeByte(0);
59 }
60
61 private Bootstrap bootstrap;
62
63
64
65
66 public void start(int port) throws IOException {
67 bootstrap = new Bootstrap();
68 bootstrap.group(new NioEventLoopGroup());
69 bootstrap.channel(NioDatagramChannel.class);
70 bootstrap.option(ChannelOption.SO_RCVBUF, 65536);
71 bootstrap.handler(new ChannelInitializer<DatagramChannel>() {
72
73 @Override
74 protected void initChannel(DatagramChannel ch) throws Exception {
75 ch.pipeline().addLast(new SimpleChannelInboundHandler<DatagramPacket>() {
76 @Override
77 public void channelActive(ChannelHandlerContext ctx) throws Exception {
78 ctx.attr(STATE_ATTRIBUTE).set(State.WAIT_FOR_FIRST_BYTE_LENGTH);
79 }
80
81 @Override
82 protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket message) throws Exception {
83 ByteBuf buffer = message.content();
84 State state = ctx.attr(STATE_ATTRIBUTE).get();
85 int length = 0;
86 Attribute<Integer> lengthAttribute = ctx.attr(LENGTH_ATTRIBUTE);
87
88 if (lengthAttribute.get() != null) {
89 length = lengthAttribute.get();
90 }
91
92 while (buffer.readableBytes() > 0) {
93 switch (state) {
94 case WAIT_FOR_FIRST_BYTE_LENGTH:
95 length = (buffer.readByte() & 255) << 24;
96 state = State.WAIT_FOR_SECOND_BYTE_LENGTH;
97 break;
98
99 case WAIT_FOR_SECOND_BYTE_LENGTH:
100 length += (buffer.readByte() & 255) << 16;
101 state = State.WAIT_FOR_THIRD_BYTE_LENGTH;
102 break;
103
104 case WAIT_FOR_THIRD_BYTE_LENGTH:
105 length += (buffer.readByte() & 255) << 8;
106 state = State.WAIT_FOR_FOURTH_BYTE_LENGTH;
107 break;
108
109 case WAIT_FOR_FOURTH_BYTE_LENGTH:
110 length += (buffer.readByte() & 255);
111 state = State.READING;
112
113 if ((length == 0) && (buffer.readableBytes() == 0)) {
114 ctx.writeAndFlush(new DatagramPacket(ACK.retain(1).resetReaderIndex(), message.sender()));
115 state = State.WAIT_FOR_FIRST_BYTE_LENGTH;
116 }
117 break;
118
119 case READING:
120 int remaining = buffer.readableBytes();
121
122 if (length > remaining) {
123 length -= remaining;
124 buffer.skipBytes(remaining);
125 } else {
126 buffer.skipBytes(length);
127 ctx.writeAndFlush(new DatagramPacket(ACK.retain(1).resetReaderIndex(), message.sender()));
128 state = State.WAIT_FOR_FIRST_BYTE_LENGTH;
129 length = 0;
130 }
131 }
132 }
133
134 ctx.attr(STATE_ATTRIBUTE).set(state);
135 ctx.attr(LENGTH_ATTRIBUTE).set(length);
136 }
137 });
138 }
139 });
140 bootstrap.bind(port);
141 }
142
143
144
145
146 public void stop() throws IOException {
147 bootstrap.group().shutdownGracefully();
148 }
149 }