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.tcp;
21
22 import java.io.IOException;
23 import java.net.InetSocketAddress;
24 import java.util.HashMap;
25 import java.util.Map;
26
27 import org.apache.mina.core.BenchmarkServer;
28 import org.apache.mina.core.CounterFilter;
29 import org.jboss.netty.bootstrap.ServerBootstrap;
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.WriteCompletionEvent;
43 import org.jboss.netty.channel.group.ChannelGroup;
44 import org.jboss.netty.channel.group.DefaultChannelGroup;
45 import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
46
47
48
49
50
51 public class Netty3TcpBenchmarkServer 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 = Netty3TcpBenchmarkServer.class.getName() + ".state";
64
65 private static final String LENGTH_ATTRIBUTE = Netty3TcpBenchmarkServer.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 NioServerSocketChannelFactory();
99 ServerBootstrap bootstrap = new ServerBootstrap(factory);
100 bootstrap.setOption("receiveBufferSize", 128 * 1024);
101 bootstrap.setOption("tcpNoDelay", true);
102 bootstrap.setPipelineFactory(new ChannelPipelineFactory() {
103 public ChannelPipeline getPipeline() throws Exception {
104 return Channels.pipeline(new SimpleChannelUpstreamHandler() {
105 @Override
106 public void childChannelOpen(ChannelHandlerContext ctx, ChildChannelStateEvent e) throws Exception {
107 System.out.println("childChannelOpen");
108 setAttribute(ctx, STATE_ATTRIBUTE, State.WAIT_FOR_FIRST_BYTE_LENGTH);
109 }
110
111 @Override
112 public void channelOpen(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
113 System.out.println("channelOpen");
114 setAttribute(ctx, STATE_ATTRIBUTE, State.WAIT_FOR_FIRST_BYTE_LENGTH);
115 allChannels.add(ctx.getChannel());
116 }
117
118 public void writeComplete(ChannelHandlerContext ctx, WriteCompletionEvent e) throws Exception {
119 CounterFilter.messageSent.getAndIncrement();
120 }
121
122 @Override
123 public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
124 if (e.getMessage() instanceof ChannelBuffer) {
125 ChannelBuffer buffer = (ChannelBuffer) e.getMessage();
126
127 State state = (State) getAttribute(ctx, STATE_ATTRIBUTE);
128 int length = 0;
129 if (getAttributesMap(ctx).containsKey(LENGTH_ATTRIBUTE)) {
130 length = (Integer) getAttribute(ctx, LENGTH_ATTRIBUTE);
131 }
132 while (buffer.readableBytes() > 0) {
133 switch (state) {
134 case WAIT_FOR_FIRST_BYTE_LENGTH:
135 length = (buffer.readByte() & 255) << 24;
136 state = State.WAIT_FOR_SECOND_BYTE_LENGTH;
137 break;
138 case WAIT_FOR_SECOND_BYTE_LENGTH:
139 length += (buffer.readByte() & 255) << 16;
140 state = State.WAIT_FOR_THIRD_BYTE_LENGTH;
141 break;
142 case WAIT_FOR_THIRD_BYTE_LENGTH:
143 length += (buffer.readByte() & 255) << 8;
144 state = State.WAIT_FOR_FOURTH_BYTE_LENGTH;
145 break;
146 case WAIT_FOR_FOURTH_BYTE_LENGTH:
147 length += (buffer.readByte() & 255);
148 state = State.READING;
149 if ((length == 0) && (buffer.readableBytes() == 0)) {
150 ctx.getChannel().write(ACK.slice());
151 state = State.WAIT_FOR_FIRST_BYTE_LENGTH;
152 }
153 break;
154 case READING:
155 int remaining = buffer.readableBytes();
156 if (length > remaining) {
157 length -= remaining;
158 buffer.skipBytes(remaining);
159 } else {
160 buffer.skipBytes(length);
161 ctx.getChannel().write(ACK.slice());
162 state = State.WAIT_FOR_FIRST_BYTE_LENGTH;
163 length = 0;
164 }
165 }
166 }
167 setAttribute(ctx, STATE_ATTRIBUTE, state);
168 setAttribute(ctx, LENGTH_ATTRIBUTE, length);
169 }
170 }
171
172 @Override
173 public void channelClosed(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
174 allChannels.remove(ctx.getChannel());
175 }
176
177 @Override
178 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
179 e.getCause().printStackTrace();
180 }
181 });
182 }
183 });
184 allChannels.add(bootstrap.bind(new InetSocketAddress(port)));
185 }
186
187
188
189
190 public void stop() throws IOException {
191 allChannels.disconnect().awaitUninterruptibly();
192 factory.releaseExternalResources();
193 }
194 }