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 java.io.IOException;
23 import java.net.InetSocketAddress;
24 import java.net.SocketAddress;
25 import java.util.HashMap;
26 import java.util.Map;
27
28 import org.apache.mina.core.BenchmarkServer;
29 import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
30 import org.jboss.netty.buffer.ChannelBuffer;
31 import org.jboss.netty.buffer.ChannelBuffers;
32 import org.jboss.netty.channel.ChannelFactory;
33 import org.jboss.netty.channel.ChannelHandlerContext;
34 import org.jboss.netty.channel.ChannelPipeline;
35 import org.jboss.netty.channel.ChannelPipelineFactory;
36 import org.jboss.netty.channel.ChannelStateEvent;
37 import org.jboss.netty.channel.Channels;
38 import org.jboss.netty.channel.ChildChannelStateEvent;
39 import org.jboss.netty.channel.ExceptionEvent;
40 import org.jboss.netty.channel.MessageEvent;
41 import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
42 import org.jboss.netty.channel.group.ChannelGroup;
43 import org.jboss.netty.channel.group.DefaultChannelGroup;
44 import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;
45
46
47
48
49
50
51 public class Netty3UdpBenchmarkServer implements BenchmarkServer {
52
53 private static enum State {
54 WAIT_FOR_FIRST_BYTE_LENGTH, WAIT_FOR_SECOND_BYTE_LENGTH, WAIT_FOR_THIRD_BYTE_LENGTH, WAIT_FOR_FOURTH_BYTE_LENGTH, READING
55 }
56
57 private static final ChannelBuffer ACK = ChannelBuffers.buffer(1);
58
59 static {
60 ACK.writeByte(0);
61 }
62
63 private static final String STATE_ATTRIBUTE = Netty3UdpBenchmarkServer.class.getName() + ".state";
64
65 private static final String LENGTH_ATTRIBUTE = Netty3UdpBenchmarkServer.class.getName() + ".length";
66
67 private ChannelFactory factory;
68
69 private ChannelGroup allChannels = new DefaultChannelGroup();
70
71
72
73
74
75
76
77 protected static Map<String, Object> getAttributesMap(ChannelHandlerContext ctx) {
78 Map<String, Object> map = (Map<String, Object>) ctx.getAttachment();
79 if (map == null) {
80 map = new HashMap<String, Object>();
81 ctx.setAttachment(map);
82 }
83 return map;
84 }
85
86 private static void setAttribute(ChannelHandlerContext ctx, String name, Object value) {
87 getAttributesMap(ctx).put(name, value);
88 }
89
90 private static Object getAttribute(ChannelHandlerContext ctx, String name) {
91 return getAttributesMap(ctx).get(name);
92 }
93
94
95
96
97 public void start(int port) throws IOException {
98 factory = new NioDatagramChannelFactory();
99 ConnectionlessBootstrap bootstrap = new ConnectionlessBootstrap(factory);
100 bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
101 public ChannelPipeline getPipeline() throws Exception {
102 return Channels.pipeline(new SimpleChannelUpstreamHandler() {
103 @Override
104 public void childChannelOpen(ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception {
105 System.out.println("childChannelOpen");
106 setAttribute(ctx, STATE_ATTRIBUTE, State.WAIT_FOR_FIRST_BYTE_LENGTH);
107 }
108
109 @Override
110 public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
111 System.out.println("channelOpen");
112 setAttribute(ctx, STATE_ATTRIBUTE, State.WAIT_FOR_FIRST_BYTE_LENGTH);
113 allChannels.add(ctx.getChannel());
114 }
115
116 @Override
117 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
118 if (e.getMessage() instanceof ChannelBuffer) {
119 ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
120
121 State state = (State) getAttribute(ctx, STATE_ATTRIBUTE);
122 int length = 0;
123 if (getAttributesMap(ctx).containsKey(LENGTH_ATTRIBUTE)) {
124 length = (Integer) getAttribute(ctx, LENGTH_ATTRIBUTE);
125 }
126 while (buffer.readableBytes() > 0) {
127 switch (state) {
128 case WAIT_FOR_FIRST_BYTE_LENGTH:
129 length = (buffer.readByte() & 255) << 24;
130 state = State.WAIT_FOR_SECOND_BYTE_LENGTH;
131 break;
132 case WAIT_FOR_SECOND_BYTE_LENGTH:
133 length += (buffer.readByte() & 255) << 16;
134 state = State.WAIT_FOR_THIRD_BYTE_LENGTH;
135 break;
136 case WAIT_FOR_THIRD_BYTE_LENGTH:
137 length += (buffer.readByte() & 255) << 8;
138 state = State.WAIT_FOR_FOURTH_BYTE_LENGTH;
139 break;
140 case WAIT_FOR_FOURTH_BYTE_LENGTH:
141 length += (buffer.readByte() & 255);
142 state = State.READING;
143 if ((length == 0) && (buffer.readableBytes() == 0)) {
144 ctx.getChannel().write(ACK.slice());
145 state = State.WAIT_FOR_FIRST_BYTE_LENGTH;
146 }
147 break;
148 case READING:
149 int remaining = buffer.readableBytes();
150 if (length > remaining) {
151 length -= remaining;
152 buffer.skipBytes(remaining);
153 } else {
154 buffer.skipBytes(length);
155 SocketAddress remoteAddress = e.getRemoteAddress();
156 ctx.getChannel().write(ACK.slice(), remoteAddress);
157 state = State.WAIT_FOR_FIRST_BYTE_LENGTH;
158 length = 0;
159 }
160 }
161 }
162 setAttribute(ctx, STATE_ATTRIBUTE, state);
163 setAttribute(ctx, LENGTH_ATTRIBUTE, length);
164 }
165 }
166
167 @Override
168 public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
169 allChannels.remove(ctx.getChannel());
170 }
171
172 @Override
173 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
174 e.getCause().printStackTrace();
175 }
176 });
177 }
178 });
179 allChannels.add(bootstrap.bind(new InetSocketAddress(port)));
180 }
181
182
183
184
185 public void stop() throws IOException {
186 allChannels.disconnect().awaitUninterruptibly();
187 factory.shutdown();
188 factory.releaseExternalResources();
189 }
190 }