2014年3月17日 星期一

Non-Blocking UDP Server Sample

Non-Blocking UDP Server 模擬結果:
備註:選定Port後啟動Server等待Client發送,收到Client訊息後,Server會回覆給Client

Non-Blocking UDP Server範例如下:
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.apache.http.conn.util.InetAddressUtils;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener
{
 private TextView tvDisplay,tvLocalIP;
 private EditText etPort;
 private Button btStartOrClose;
 private boolean isRunning = false;
 private DatagramChannel mServerChannel;
 private Selector mSelector;
 private int MAX_PACKET_SIZE = 1024;
 private int port = 0;
 @Override
 protected void onCreate(Bundle savedInstanceState)
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  //initial UI component
  tvDisplay = (TextView) findViewById(R.id.xml_tvDisplay);
  tvLocalIP = (TextView) findViewById(R.id.xml_tvIP);
  etPort = (EditText) findViewById(R.id.xml_etPort);
  btStartOrClose = (Button) findViewById(R.id.xml_btStart);
  btStartOrClose.setOnClickListener(this);
  
  //get IP address and display it
  String LocalIPAddress = "";
        try 
        {
            List<NetworkInterface> interfaces = Collections.list(NetworkInterface.getNetworkInterfaces());
            for (NetworkInterface intf : interfaces) 
            {
                List<InetAddress> addrs = Collections.list(intf.getInetAddresses());
                for (InetAddress addr : addrs) 
                {
                    if (!addr.isLoopbackAddress()) 
                    {
                        String sAddr = addr.getHostAddress().toUpperCase();
                        boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr); 
                        if(isIPv4) 
                         LocalIPAddress =  sAddr;
                        else 
                        {
                         int delim = sAddr.indexOf('%'); // drop ip6 port suffix
                         LocalIPAddress = delim<0 ? sAddr : sAddr.substring(0, delim);
                        }
                    }
                }
            }
        }
        catch(SocketException e)
        { 
         Log.e("NIOUDP_Server","Get network informaton fail.");
        } 
        
  if(LocalIPAddress != "")
   tvLocalIP.setText(LocalIPAddress);
  //
 }
 
 @Override
 protected void onDestroy() 
 {
  // TODO Auto-generated method stub
  super.onDestroy();
  //stop udp server process
  isRunning = false;
  //
 }

 @Override
 public void onClick(View v) 
 {
  // TODO Auto-generated method stub
  switch(v.getId())
  {
   case R.id.xml_btStart:
     if(etPort.getText().length() != 0 && etPort.getText().toString() != null)
     {
      if(!isRunning)
      {
       btStartOrClose.setText("Close");
       port = Integer.valueOf(etPort.getText().toString());
       isRunning = true;
       new Thread(startUDPServerProcess).start();
      }
      else
      {
       btStartOrClose.setText("Start");
       //stop udp server process
       isRunning = false;
       //
      }
     }
     break;
   default:
     break;
  }
 }
  
 //start udp server process
 private Runnable startUDPServerProcess = new Runnable()
  {
   @Override
   public void run() 
   {
    // TODO Auto-generated method stub
    try 
    {
     //open the channel and the selector
     try
     {
      mSelector = Selector.open();
      mServerChannel = DatagramChannel.open();
      mServerChannel.configureBlocking(false);
     }
     catch(IOException e)
     {
      e.printStackTrace();
      Log.e("NIOUDP_Server","Selector opening or channel opening fail.");
     }
     //
     //start server to bind the port and register channel to listen reading or writing event
     mServerChannel.socket().setReuseAddress(true);
     mServerChannel.socket().bind(new InetSocketAddress(port));
     mServerChannel.register(mSelector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
     //
     //the selector select the channel event and receive message
     ByteBuffer mReceiveBuffer = ByteBuffer.allocate(MAX_PACKET_SIZE);  
     while(isRunning)
     {
      try 
      {
       mSelector.select();
       Iterator<SelectionKey> mIterator = mSelector.selectedKeys().iterator();
       while(mIterator.hasNext())
       {
        SelectionKey mKey = mIterator.next();
        if(mKey.isReadable())
        {
         mReceiveBuffer.clear();
         DatagramChannel mChannel = (DatagramChannel) mKey.channel();
         SocketAddress mAddress = mChannel.receive(mReceiveBuffer);
         if (mAddress != null) 
         {
          mReceiveBuffer.flip();
          int mSize = mReceiveBuffer.limit();
          byte[] mMessageBuffer = new byte[mSize];
          mReceiveBuffer.get(mMessageBuffer);
          final String message = mAddress+":\r\n"+new String(mMessageBuffer);
         
          //display the message which is received 
          runOnUiThread(new Runnable()
          {
           @Override
           public void run() 
           {
            // TODO Auto-generated method stub
            String displayMessage = tvDisplay.getText().toString();
            if(displayMessage.contains("Waiting")|| tvDisplay.getLineCount() > 6)
             tvDisplay.setText("");
            displayMessage = tvDisplay.getText().toString()+"\r\n"+message;
            tvDisplay.setText(displayMessage);
           }
          });
          //
         
          //send the request message
          try 
          {
           String sendMessage = "OK!!I have got your message!!";
           ByteBuffer mSendBuffer = ByteBuffer.allocate(MAX_PACKET_SIZE);
           mSendBuffer.put(sendMessage.getBytes());
           mSendBuffer.flip();
           int size = mServerChannel.send(mSendBuffer, mAddress);
           if(size == 0)
           {
            mKey.interestOps(mKey.interestOps() ^ SelectionKey.OP_WRITE);
            Log.e("NIOUDP_Server","ByteBuffer is full.");
           }
          } 
          catch (IOException e)
          {
           // TODO Auto-generated catch block
           e.printStackTrace();
           Log.e("NIOUDP_Server","Channel is already closed.");
          }
          //
         }
        }
        else if(mKey.isWritable())
        {
         mKey.interestOps(mKey.interestOps() ^ SelectionKey.OP_WRITE);
        }
      }
      mIterator.remove();
     } 
     catch (IOException e) 
     {
      // TODO Auto-generated catch block
      e.printStackTrace();
      Log.e("NIOUDP_Server","The selector selects fail.");
     }
    }
    //
     
    //close channel and selector
    try 
    {
     mSelector.close();
     mServerChannel.close();
     mSelector = null;
     mServerChannel = null;
    } 
    catch (IOException e) 
    {
     // TODO Auto-generated catch block
     e.printStackTrace();
     Log.e("NIOUDP_Server","Close socket fail.");
    }
    //
   } 
   catch (SocketException s) 
   {
    // TODO Auto-generated catch block
    s.printStackTrace();
    Log.e("NIOUDP_Server","Socket binding fail.");
    isRunning = false;
       return;
   }
   catch(ClosedChannelException c)
   {
    c.printStackTrace();
    Log.e("NIOUDP_Server","Channel registering fail.");
    isRunning = false;
    return;
   }
    
  }
  };
  //
}

activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/xml_etStart"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity" >

    <TextView
        android:id="@+id/xml_tvDisplay"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:lines="8"
        android:maxLines="8"
        android:text="Waiting for connecting..."
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <Button
        android:id="@+id/xml_btStart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_below="@+id/xml_tvDisplay"
        android:text="Start" />

    <TextView
        android:id="@+id/xml_tvPort"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/xml_etPort"
        android:layout_alignBottom="@+id/xml_etPort"
        android:layout_alignParentLeft="true"
        android:text="Port:"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/xml_etPort"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/xml_btStart"
        android:layout_alignBottom="@+id/xml_btStart"
        android:layout_toLeftOf="@+id/xml_btStart"
        android:layout_toRightOf="@+id/xml_tvPort"
        android:ems="10"
        android:inputType="number" />

    <TextView
        android:id="@+id/xml_tvLocalIP"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/xml_btStart"
        android:text="Local IP: "
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/xml_tvIP"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/xml_btStart"
        android:layout_toRightOf="@+id/xml_tvLocalIP"
        android:text="0.0.0.0"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.nio_udpclient"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="16" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.nio_udpclient.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

沒有留言 :

張貼留言