UDP(短连接)---用户数据报协议,是一个简单的面向数据报的运输层协议。UDP不提供可靠性,它只是把应用程序传给IP层的数据报发送出去,但是并不能保证它们能到达目的地。由于UDP在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。
TCP(长连接)---传输控制协议,提供的是面向连接、可靠的字节流服务。当客户和服务器彼此交换数据前,必须先在双方之间建立一个TCP连接,之后才能传输数据。TCP提供超时重发,丢弃重复数据,检验数据,流量控制等功能,保证数据能从一端传到另一端。
下面介绍一下将要实现的功能UDP向TCP之间的做的转发:
接下来各个类的代码如下:
Main类的代码如下:
package com.hisoft.netty;
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
BlockingQueue
static SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd HH:mm:ss");
public View(BlockingQueue
{
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
BlockingQueue
ExecutorService es = Executors.newSingleThreadExecutor();
public Transfer(BlockingQueue
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
protected void initChannel(Channel arg0)
throws Exception
{
System.out.println("init");
}
}
}
这个Transfer类最关键的地方就是能够实现重连接的功能,代码如下:
Transfer.tcpc = Transfer.tcpBoot.connect(Transfer.tcpip, Transfer.tcpport).sync().channel();
希望对需要的朋友有所帮助。