Netty4实现UDP向TCP转发

        UDP(短连接)---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快

        TCP(长连接)---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。 

下面介绍一下将要实现的功能UDP向TCP之间的做的转发:

                                                        

     整体效果如下:      Netty4实现UDP向TCP转发_第1张图片                                                                                                                                                                                             

                                                                           Netty4实现UDP向TCP转发_第2张图片                                         

接下来各个类的代码如下:

Main类的代码如下:

package com.hisoft.netty;


import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.SynchronousQueue;


import com.hisoft.netty.change.Changer;
import com.hisoft.netty.change.ChangerImpl;
import com.hisoft.transfer.Transfer;


public class Main
{
  static Transfer tran;
  static ExecutorService es = Executors.newSingleThreadExecutor();
  static BlockingQueue q1 = new SynchronousQueue();
  static BlockingQueue q2 = new SynchronousQueue();
  static Changer changer;


  public static void main(String[] args)
  {
    changer = new ChangerImpl();
    tran = new Transfer(q1, q2, changer);
    Future future = es.submit(new Callable()
    {
      public Object call() {
        new View(Main.q2, Main.q1);
        return Boolean.valueOf(true);
      } } );
    try {
      future.get();
    } catch (InterruptedException e1) {
      e1.printStackTrace();
    } catch (ExecutionException e1) {
      e1.printStackTrace();
    }
  }
}

Util类的代码如下:

package com.hisoft.netty;
public class Util
{
  public static String bytesToHexString(byte[] src)
  {
    StringBuilder stringBuilder = new StringBuilder("");
    if ((src == null) || (src.length <= 0)) {
      return null;
    }
    for (int i = 0; i < src.length; i++) {
      int v = src[i] & 0xFF;
      String hv = Integer.toHexString(v);
      if (hv.length() < 2) {
        stringBuilder.append(0);
      }
      stringBuilder.append(hv);
    }
    return stringBuilder.toString();
  }
}

View类的代码如下:

package com.hisoft.netty;


import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;


public class View extends JFrame
{
  static JFrame jf = new JFrame("UDP转TCP");
  static JPanel jp = new JPanel();
  static JLabel udpname = new JLabel("UPD端口");
  static JLabel tcpname = new JLabel("TCP地址");
  static JTextField udp = new JTextField(12);
  static JTextField tcp = new JTextField(12);
  static JTextArea area = new JTextArea();
  static JButton ok = new JButton("ok");
  static JButton cen = new JButton("cencel");


  ExecutorService es = Executors.newSingleThreadExecutor();
  BlockingQueue inQueue;
  BlockingQueue outQueue;
  static SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");


  public View(BlockingQueue inQ, BlockingQueue outQ)
  {
    jp.setLayout(null);
    udpname.setBounds(10, 10, 50, 30);
    jp.add(udpname);
    udp.setBounds(70, 10, 160, 30);
    jp.add(udp);
    tcpname.setBounds(10, 60, 50, 30);
    jp.add(tcpname);
    tcp.setBounds(70, 60, 160, 30);
    jp.add(tcp);
    ok.setBounds(30, 100, 80, 30);
    jp.add(ok);
    cen.setBounds(120, 100, 80, 30);
    jp.add(cen);
    area.setBounds(10, 150, 230, 230);
    jp.add(area);
    area.setLineWrap(true);
    area.setWrapStyleWord(true);
    area.setText(" no data");
    jf.add(jp);
    jf.setVisible(true);
    jf.setSize(250, 400);
    jf.setDefaultCloseOperation(3);
    jf.setLocation(500, 270);
    ok.addMouseListener(new MouseListener()
    {
      public void mouseReleased(MouseEvent e) {
      }


      public void mousePressed(MouseEvent e) {
      }


      public void mouseExited(MouseEvent e) {
      }


      public void mouseEntered(MouseEvent e) {
      }


      public void mouseClicked(MouseEvent e) {
        try {
          View.this.outQueue.put("start:" + View.udp.getText() + ":" + View.tcp.getText());
        } catch (Exception e1) {
          View.area.setText(e1.getMessage());
        }
      }
    });
    cen.addMouseListener(new MouseListener()
    {
      public void mouseReleased(MouseEvent e) {
      }


      public void mousePressed(MouseEvent e) {
      }


      public void mouseExited(MouseEvent e) {
      }


      public void mouseEntered(MouseEvent e) {
      }


      public void mouseClicked(MouseEvent e) {
        try {
          View.this.outQueue.put("stop");
        } catch (Exception e1) {
          View.area.setText(e1.getMessage());
        }
      }
    });
    this.inQueue = inQ;
    this.outQueue = outQ;
    this.es.submit(new Runnable() {
      public void run() {
        while (true)
          try {
            String text = (String)View.this.inQueue.take();
            text = View.sdf.format(new Date()) + "\n" + text;
            View.area.setText(text);
            continue; } catch (Exception e) {
            e.printStackTrace();
          }
      }
    });
  }
}

Changer和ChangerImpl这两个类在此项目里没有用到,只是为了在以后做扩展使用,代码如下:

package com.hisoft.netty.change;
public abstract interface Changer
{
  public abstract byte[] change(byte[] paramArrayOfByte);
}

package com.hisoft.netty.change;
public class ChangerImpl
  implements Changer
{
  public byte[] change(byte[] data)
  {
    byte[] returnData = null;


    switch (selectProtocol(data))
    {
    case 1:
      break;
    case 2:
      break;
    }


    return returnData;
  }


  public int selectProtocol(byte[] data)
  {
    return 0;
  }
}

Transfer类的代码如下:

package com.cnpc.netty.transfer;


import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.MessageToMessageDecoder;
import io.netty.handler.codec.bytes.ByteArrayDecoder;
import io.netty.handler.codec.bytes.ByteArrayEncoder;


import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;


import com.cnpc.netty.change.Changer;


public class Transfer
{
  public static int udpport;
  public static String tcpip;
  public static int tcpport;
  static Bootstrap boot;
  static EventLoopGroup group;
  static EventLoopGroup tcpGroup;
  static Bootstrap tcpBoot;
  static Channel udpc;
  static Channel tcpc;
  static Changer changer;
  BlockingQueue inQueue;
  BlockingQueue outQueue;
  ExecutorService es = Executors.newSingleThreadExecutor();


  public Transfer(BlockingQueue inQ, BlockingQueue outQ, Changer changer) {
    changer = changer;
    this.inQueue = inQ;
    this.outQueue = outQ;
    this.es.submit(new Runnable()
    {
      public void run()
      {
        while (true)
          try {
            String command = (String)Transfer.this.inQueue.take();
            if (command.startsWith("start")) {
              String[] strs = command.split(":");
              Transfer.udpport = Integer.parseInt(strs[1]);
              Transfer.tcpip = strs[2];
              Transfer.tcpport = Integer.parseInt(strs[3]);
              Transfer.this.start();
              continue; } if (command.startsWith("stop")) {
              Transfer.udpc.close();
              Transfer.tcpc.close();


              continue;
            } } catch (Exception e) {
            try {
              Transfer.this.outQueue.put(e.getMessage());
            } catch (Exception e1) {
              e1.printStackTrace();
            }
          }
      }
    });
  }


  public void start()
  {
    group = new NioEventLoopGroup();
    boot = new Bootstrap();


    ((Bootstrap)((Bootstrap)((Bootstrap)((Bootstrap)((Bootstrap)((Bootstrap)boot.group(group)).channel(NioDatagramChannel.class)).option(ChannelOption.SO_BROADCAST, Boolean.valueOf(true))).option(ChannelOption.SO_REUSEADDR, Boolean.valueOf(true)))
      .handler(getInitHandle())).handler(getDataDecoder())).handler(getDataHandler());
    ChannelFuture f = boot.bind(udpport).awaitUninterruptibly();
    udpc = f.channel();
    try {
      f.get();
    } catch (InterruptedException e) {
      e.printStackTrace();
    } catch (ExecutionException e) {
      e.printStackTrace();
    } catch (Exception e) {
      e.printStackTrace();
    }


    EventLoopGroup tcpGroup = new NioEventLoopGroup();
    tcpBoot = new Bootstrap();
    try
    {
      ((Bootstrap)((Bootstrap)tcpBoot
        .group(tcpGroup))
        .channel(NioSocketChannel.class))
        .handler(new ChannelInitializer()
      {
        protected void initChannel(Channel arg0) throws Exception {
          ChannelPipeline pipeline = arg0.pipeline();
          pipeline.addLast("decoder", new ByteArrayDecoder());
          pipeline.addLast("encoder", new ByteArrayEncoder());
          Transfer.this.outQueue.put("tcp inited!");
        } } );
    } catch (Exception e) {
      e.printStackTrace();
    }
    try
    {
      this.outQueue.put("transfer server started !");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }


  public InitHandle getInitHandle() {
    return new InitHandle();
  }


  public DataHandler getDataHandler() {
    return new DataHandler();
  }


  public DataDecoder getDataDecoder() {
    return new DataDecoder();
  }


  public class DataDecoder extends MessageToMessageDecoder
  {
    public DataDecoder()
    {
    }


    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
      throws Exception
    {
      System.out.println("run decoder exceptionCaught");
      super.exceptionCaught(ctx, cause);
    }


    protected void decode(ChannelHandlerContext arg0, DatagramPacket arg1, List arg2) throws Exception {
      System.out.println(arg1.toString() + "dec");
    }
  }


  public class DataHandler extends SimpleChannelInboundHandler
  {
    public DataHandler()
    {
    }


    protected void channelRead0(ChannelHandlerContext arg0, String arg1)
      throws Exception
    {
      System.out.println("run handle read0  " + arg1);
    }


    public void channelRead(ChannelHandlerContext arg0, Object arg1)
      throws Exception
    {
      Transfer.tcpc = Transfer.tcpBoot.connect(Transfer.tcpip, Transfer.tcpport).sync().channel();
      DatagramPacket packet = (DatagramPacket)arg1;
      ByteBuf buf = (ByteBuf)packet.content();
      byte[] bb = new byte[buf.readableBytes()];
      buf.readBytes(bb);


      Transfer.tcpc.writeAndFlush(bb);
      Transfer.this.outQueue.put(new String(bb, "ASCII"));
      Transfer.tcpc.close();
      super.channelRead(arg0, arg1);
    }


    public void channelActive(ChannelHandlerContext ctx) throws Exception {
      System.out.println("run handle active");
      super.channelActive(ctx);
    }


    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
      System.out.println("run handle inActive");
      super.channelInactive(ctx);
    }


    public boolean acceptInboundMessage(Object msg)
      throws Exception
    {
      return super.acceptInboundMessage(msg);
    }


    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
      System.out.println("run handle channelReadComplete");
      super.channelReadComplete(ctx);
      ctx.flush();
    }


    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
      System.out.println("run handle channelRegistered");
      super.channelRegistered(ctx);
    }


    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
      System.out.println("run handle channelUnregistered");
      super.channelUnregistered(ctx);
    }


    public void channelWritabilityChanged(ChannelHandlerContext ctx) throws Exception {
      System.out.println("run handle channelWritabilityChanged");
      super.channelWritabilityChanged(ctx);
    }
  }


  public class InitHandle extends ChannelInitializer
  {
    public InitHandle()
    {
    }




    protected void initChannel(Channel arg0)
      throws Exception
    {
      System.out.println("init");
    }
  }
}

这个Transfer类最关键的地方就是能够实现重连接的功能,代码如下:

Transfer.tcpc = Transfer.tcpBoot.connect(Transfer.tcpip, Transfer.tcpport).sync().channel();

希望对需要的朋友有所帮助。


你可能感兴趣的:(Netty4实现UDP向TCP转发)