View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
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   * A Netty 3 based UDP server
42   * 
43   * @author <a href="http://mina.apache.org">Apache MINA Project</a>
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       * {@inheritDoc}
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      * {@inheritedDoc}
145      */
146     public void stop() throws IOException {
147         bootstrap.group().shutdownGracefully();
148     }
149 }