標籤:style blog java color 使用 os
說明:基於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; }}