netty 3.9.2 UDP協議服務器和客戶端DEMO


說明:基於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;
    }
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM