2014年3月11日 星期二

Non-Blocking mode for UDP


Non-Blocking mode for UDP
Non-Blocking UDP 指令使用方法如下:
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Iterator;
import android.content.Context;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.util.Log;

public class NIOUDPProcess 
{
 private String mRemote_IP = "";
 private String mRemote_Port = "";
 private String mReceive_Message = "";
 private int mSenderPort = -1;
 private Thread udpClientThread,udpReceiverThread,udpSenderThread;
 private int MAX_PACKET_SIZE = 1024;
 private boolean isRunning = false;
 private Context mContext;
 private DatagramChannel mSenderChannel,mReceiverChannel,mChannel;
 private DatagramSocket mSenderSocket;
 private SocketAddress mSenderAddress;
 
 public static interface NIOUDPStatusListener
 {
  void displayMessage(String message);
 }
 
 NIOUDPStatusListener mServerStatusListenerCallback;
 public NIOUDPProcess(Context context, NIOUDPStatusListener callback)
 {
  mContext = context;
  mServerStatusListenerCallback = callback;
 }

    /**
     * Start NIO receiver process thread.
     * @param The port for binding and how many lines you want to bind.
     * @return
     */
 public void startNIOUDPReceiverProcess(final int bind_port ,final int number)
 {
  udpReceiverThread = new Thread(new Runnable()
  {
   @Override
   public void run() 
   {
    // TODO Auto-generated method stub
       try 
       {
        Selector mSelector = Selector.open();
        int port = bind_port;
        
        for(int i = 0; i < number; i++)
        {
         mReceiverChannel = DatagramChannel.open( );
         mReceiverChannel.configureBlocking(false);
         mReceiverChannel.socket().bind(new InetSocketAddress(port));
         mReceiverChannel.register(mSelector, SelectionKey.OP_READ);
         port++;
        }

        isRunning = true;
     
     ByteBuffer mReceiveBuffer = ByteBuffer.allocate(MAX_PACKET_SIZE);
     while(isRunning)
      receiveProcess(mReceiveBuffer, mSelector);
    } 
       catch (SocketException e) 
       {
     // TODO Auto-generated catch block
     e.printStackTrace();
     Log.e("BK","Open socket error.");
    }
       catch (IOException e) 
       {
     // TODO Auto-generated catch block
     e.printStackTrace();
     Log.e("BK","Bind socket error.");
    }
   }
  });
  udpReceiverThread.start();
 }
 
    /**
     * Stop NIO receiver process thread.
     * @return
     */
 public void stopNIOUDPReceiverProcess()
 {
  isRunning = false;
  udpReceiverThread = null;
 }
 
    /**
     * Start NIO sender process thread.
     * @param The port and the ip for connecting.
     * @return
     */
 public void startNIOUDPSenderProcess(final String connect_ip, final int connect_port)
 {
  udpSenderThread = new Thread(new Runnable()
  {
   @Override
   public void run() 
   {
    // TODO Auto-generated method stub
       try 
       {
        mSenderPort = connect_port;
        mSenderChannel = DatagramChannel.open( );
        mSenderSocket = mSenderChannel.socket( );
        mSenderAddress = new InetSocketAddress(connect_ip, connect_port);
        mSenderChannel.socket( ).connect(mSenderAddress);
        mSenderChannel.configureBlocking(false);
       } 
       catch (SocketException e) 
       {
     // TODO Auto-generated catch block
     e.printStackTrace();
     Log.e("BK","Open socket error.");
       }
       catch (IOException e) 
       {
     // TODO Auto-generated catch block
     e.printStackTrace();
     Log.e("BK","Bind socket error.");
       }
   }
  });
  udpSenderThread.start();
 }
 
    /**
     * The process of which channel is used to receiving.
     * @param The buffer is for receiving. The selector for selecting the udp socket channel
     *        which is used to receiving.
     * @return
     */
 private void receiveProcess(ByteBuffer mReceiveBuffer, Selector mSelector)
 {
  try 
  {
   mSelector.select();
   Iterator mIterator = mSelector.selectedKeys().iterator();
   while(mIterator.hasNext())
   {
    SelectionKey mClientKey = mIterator.next();
    if(mClientKey.isReadable())
    {
      mChannel = (DatagramChannel) mClientKey.channel();
      mReceiveBuffer.clear();
      if (mChannel.receive(mReceiveBuffer) != null) 
      {
       mReceiveBuffer.flip();
       int mSize = mReceiveBuffer.limit();
       byte[] mMessageBuffer = new byte[mSize];
       mReceiveBuffer.get(mMessageBuffer);
       String message = new String(mMessageBuffer);
       decomposePacket(message);
       mServerStatusListenerCallback.displayMessage(mRemote_IP+
                  "("+mRemote_Port+")"+
                  ":"+mReceive_Message+
                  "\r\n");
      }
    }
   }
  } 
  catch (IOException e) 
  {
   // TODO Auto-generated catch block
   e.printStackTrace();
   Log.e("BK","Receive process error.");
  }
 }
 
    /**
     * The process of which channel is used to sending.
     * @param The buffer is for sending. The selector for selecting the udp socket channel
     *        which is used to sending.
     * @return
     */
 public void sendProcess(final String message)
 {
  if(mSenderChannel == null || mSenderSocket == null)
   return;
  if(mSenderSocket.isClosed())
   return;
  
  udpClientThread = new Thread(new Runnable()
  {
   @Override
   public void run() 
   {
    try 
    {
     ByteBuffer mSendBuffer = ByteBuffer.allocate(MAX_PACKET_SIZE);
     mSendBuffer.put(makePacket(getWiFiIP(),""+mSenderPort,message).getBytes());
     mSendBuffer.flip();
     mSenderChannel.send(mSendBuffer, mSenderAddress);
     mServerStatusListenerCallback.displayMessage("Me:"+message+"\r\n");
    }
    catch (IOException e) 
    {
     // TODO Auto-generated catch block
     e.printStackTrace();
     Log.e("BK","Send process error.");
    }
   }
  });
  udpClientThread.start();
 }
 
    /**
     * Make the special format packet including ip ,port and message.
     * @param The ip address ,port ,message of sender. 
     * @return The composed packet.
     */
 public String makePacket(String ip, String port, String message)
 {
  String section = "\r\n\r\n";
  String return_Str = "ip:" + ip + section+
                "port:" + port + section+
                "message:" + message + section;
  return return_Str;
 }
 
    /**
     * Get the Wi-Fi ip address by using the WifiManager. 
     * @return The ip address of Wi-Fi.
     */
 public String getWiFiIP()
 {
  WifiManager wm = (WifiManager)  mContext.getSystemService( Context.WIFI_SERVICE);
        WifiInfo wifiInf = wm.getConnectionInfo();
        long ip = wifiInf.getIpAddress();
        if( ip != 0 )
               return String.format( "%d.%d.%d.%d",
                      (ip & 0xff),
                      (ip >> 8 & 0xff),
                      (ip >> 16 & 0xff),
                      (ip >> 24 & 0xff));
        else
         return "0.0.0.0";
 }
 
 /**
     * Decompose the packet for getting remote ip ,remote port and remote message. 
     * @return
     */
 public void decomposePacket(String receive_message)
 {
  String[] spilt_message = receive_message.split("\r\n\r\n");
  mRemote_IP = spilt_message[0].substring(spilt_message[0].indexOf(":")+1,
                                    spilt_message[0].length());
  mRemote_Port = spilt_message[1].substring(spilt_message[1].indexOf(":")+1,
                                      spilt_message[1].length());
  mReceive_Message = spilt_message[2].substring(spilt_message[2].indexOf(":")+1,
                                          spilt_message[2].length());
 }
}

沒有留言 :

張貼留言