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 }