说明:基于netty 3.9.2的udp协议实现的(如果你使用的版本是4.X或5.X,请参考其他方法);程序的逻辑结构是,客户端发送给服务端一串数据,服务器端返回给客户端“A”。在进行游戏开发时需要对udp的丢包进行处理,可以利用服务器端的返回值进行相关处理,以确定是否重发,这方面具体没有实现。
文章结构:
一、服务器端
1、UDPServer
2、UdpChannelPipelineFactory
3、UDPServerHandler
二、客户端
1、UDPClient
2、UDPClientChannelPipelineFactory
3、UDPClientHandler
三、ScanGetPort获取一个可用的端口号
一、服务器端
1、UDPServer
初始化一个ConnectionlessBootstrap,setPipelineFactory,绑定一个端口号。ScanGetPort是一个工具类就是,获取一个可用的端口号,源代码在最后面贴出。
package com.ls.udp.server; import java.net.InetSocketAddress; import java.util.concurrent.Executors; import org.jboss.netty.bootstrap.ConnectionlessBootstrap; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; import com.andy.server.util.ScanGetPort; public class UDPServer { public final int PORT; public UDPServer(int port){ PORT=port; } private ConnectionlessBootstrap bootstrap; void start(){ //init the bootstrap bootstrap=new ConnectionlessBootstrap(new NioDatagramChannelFactory(Executors.newCachedThreadPool())); bootstrap.setPipelineFactory(new UdpChannelPipelineFactory()); bootstrap.bind(new InetSocketAddress(PORT)); System.out.println("server start at:"+":"+PORT); } public static void main(String[] args) { /* * 获取一个可用的端口号 */ int port= new ScanGetPort().getPot(8080); new UDPServer(port).start(); } }
2、UdpChannelPipelineFactory
注册一个handler
package com.ls.udp.server; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; public class UdpChannelPipelineFactory implements ChannelPipelineFactory{ /** * set the channel pipeline * */ @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("handler", new UDPServerHandler()); return pipeline; } }
3、UDPServerHandler
handler类
package com.ls.udp.server; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.DynamicChannelBuffer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; public class UDPServerHandler extends SimpleChannelUpstreamHandler{ /** * 对于ChannelHandler, * 是UDP与TCP区别的核心所在。 * 大家都知道UDP是无连接的, * 也就是说你通过 MessageEvent 参数对象的 getChannel() 方法获取当前会话连接, * 但是其 isConnected() 永远都返回 false。 * UDP 开发中在消息获取事件回调方法中, * 获取了当前会话连接 channel 对象后可直接通过 channel 的 write 方法发送数据给对端 channel.write(message, remoteAddress), * 第一个参数仍然是要发送的消息对象, * 第二个参数则是要发送的对端 SocketAddress 地址对象。 * 这里最需要注意的一点是SocketAddress,在TCP通信中我们可以通过channel.getRemoteAddress()获得, * 但在UDP通信中,我们必须从MessageEvent中通过调用getRemoteAddress()方法获得对端的SocketAddress 地址。 */ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ChannelBuffer buffer = (ChannelBuffer)e.getMessage(); byte[] recByte=buffer.copy().toByteBuffer().array(); String msg=new String(recByte); System.out.println("from client:"+msg); ChannelBuffer responseBuffer= new DynamicChannelBuffer(1); responseBuffer.writeBytes("A".getBytes()); //write to the client e.getChannel().write(responseBuffer, e.getRemoteAddress()); super.messageReceived(ctx, e); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { super.exceptionCaught(ctx, e); } }
二、客户端
(基本结构和服务器端很像,不再赘述)
1、UDPClient
package com.ls.udp.client; import java.net.InetSocketAddress; import java.util.Scanner; import org.jboss.netty.bootstrap.ConnectionlessBootstrap; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.DynamicChannelBuffer; import org.jboss.netty.channel.Channel; import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory; public class UDPClient { private ConnectionlessBootstrap bootstrap; private Channel channel; public void start(){ //init the bootstrap bootstrap=new ConnectionlessBootstrap(new NioDatagramChannelFactory()); bootstrap.setPipelineFactory(new UDPClientChannelPipelineFactory()); bootstrap.setOption("localAddress", new InetSocketAddress(10001)); channel=bootstrap.bind(); } public void writebytes(byte[] bt,InetSocketAddress isa){ if(bootstrap==null){ this.start(); } ChannelBuffer responseBuffer= new DynamicChannelBuffer(12); responseBuffer.writeBytes(bt); channel.write(responseBuffer, isa); } public static void main(String[] args) { UDPClient uClient=new UDPClient(); Scanner scanner=new Scanner(System.in); String lienString=scanner.nextLine(); while(!lienString.equals("bye")){ uClient.writebytes(lienString.getBytes(), new InetSocketAddress("192.168.1.107",8080)); lienString=scanner.nextLine(); } } }
2、UDPClientChannelPipelineFactory
package com.ls.udp.client; import org.jboss.netty.channel.ChannelPipeline; import org.jboss.netty.channel.ChannelPipelineFactory; import org.jboss.netty.channel.Channels; public class UDPClientChannelPipelineFactory implements ChannelPipelineFactory{ /** * set the channel pipeline * */ @Override public ChannelPipeline getPipeline() throws Exception { ChannelPipeline pipeline = Channels.pipeline(); pipeline.addLast("handler", new UDPClientHandler()); return pipeline; } }
3、UDPClientHandler
package com.ls.udp.client; import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.channel.ChannelHandlerContext; import org.jboss.netty.channel.ExceptionEvent; import org.jboss.netty.channel.MessageEvent; import org.jboss.netty.channel.SimpleChannelUpstreamHandler; public class UDPClientHandler extends SimpleChannelUpstreamHandler{ @Override public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception { ChannelBuffer buffer = (ChannelBuffer)e.getMessage(); byte[] recByte=buffer.copy().toByteBuffer().array(); String msg=new String(recByte); System.out.println("from server:"+msg); super.messageReceived(ctx, e); } @Override public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception { super.exceptionCaught(ctx, e); } }
三、ScanGetPort获取一个可用的端口号
package com.andy.server.util; import java.io.IOException; import java.net.ServerSocket; /** * get the port * @author red * */ public class ScanGetPort { public synchronized int getPot(int first){ for(int i=first;i<65535;++i){ ServerSocket ss=null; try { ss= new ServerSocket(i); } catch (IOException e) { //e.printStackTrace(); }finally{ if(ss!=null){ if(ss.isBound()){ try { ss.close(); System.out.println(i); return i; } catch (IOException e) { e.printStackTrace(); } } } } } return -1; } }
netty 3.9.2 UDP协议服务器和客户端DEMO
时间: 2024-09-30 18:37:23