2014年3月17日 星期一

Non-Blocking UDP Client Sample

Non-Blocking UDP Client 模擬結果:
備註:輸入IP與Port後啟動Client,發送任意訊息後,Client會收到Server的回覆

MainActivity.java
import java.io.IOException;
import java.net.InetSocketAddress;
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.Iterator;
import android.os.Bundle;
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;
import android.app.Activity;

public class MainActivity extends Activity implements OnClickListener 
{
 private TextView tvDisplay;
 private EditText etPort,etIP,etMessage;
 private Button btStartOrClose,btSend;
 private boolean isRunning = false;
 private DatagramChannel mClientChannel;
 private Selector mSelector;
 private int MAX_PACKET_SIZE = 1024;
 private InetSocketAddress mRemoteAddress;
 private int port = 0;
 private String ip = "0.0.0.0";
 private String send_message = "";
 @Override
 protected void onCreate(Bundle savedInstanceState) 
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  //initial UI component
  tvDisplay = (TextView) findViewById(R.id.xml_tvDisplay);
  etPort = (EditText) findViewById(R.id.xml_etPort);
  etIP = (EditText) findViewById(R.id.xml_etIP);
  etMessage = (EditText) findViewById(R.id.xml_etMessage);
  btStartOrClose = (Button) findViewById(R.id.xml_btStartOrClose);
  btSend = (Button) findViewById(R.id.xml_btSend);
  btSend.setOnClickListener(this);
  btStartOrClose.setOnClickListener(this);
  //
 }
 
 @Override
 protected void onDestroy() 
 {
  // TODO Auto-generated method stub
  super.onDestroy();
  //stop udp client process
  isRunning = false;
  //
 }

 @Override
 public void onClick(View v) 
 {
  // TODO Auto-generated method stub
  switch(v.getId())
  {
   case R.id.xml_btStartOrClose:
    
     if(etIP.getText().length() != 0 && etPort.getText().length() != 0)
     {
      if(!isRunning)
      {
       btStartOrClose.setText("Close");
       ip = etIP.getText().toString();
       port = Integer.valueOf(etPort.getText().toString());
       isRunning = true;
       new Thread(startUDPClientProcess).start();
      }
      else
      {
       btStartOrClose.setText("Start");
       //stop udp client process
       isRunning = false;
       //
      }
     }
     break;
   case R.id.xml_btSend:
     if(etMessage.getText().length() != 0)
     {
      send_message = etMessage.getText().toString();
      if(mRemoteAddress==null)
       return;
      new Thread(sendMessageProcess).start();
     }
     break;
      default:
        break;
  }
 }
 
 //start udp client process
 private Runnable startUDPClientProcess = new Runnable()
  {
   @Override
   public void run() 
   {
    // TODO Auto-generated method stub
    try 
    {
     mRemoteAddress = new InetSocketAddress(ip,port);
     try
     {
      mSelector = Selector.open();
      mClientChannel = DatagramChannel.open();
      mClientChannel.configureBlocking(false);
      mClientChannel.connect(mRemoteAddress);
     }
     catch(IOException e)
     {
      e.printStackTrace();
      Log.e("NIOUDP_Client","Selector opening or channel opening fail.");
     }
     mClientChannel.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();
         int len = mChannel.read(mReceiveBuffer);
         if (len != 0) 
         {
          mReceiveBuffer.flip();
          int mSize = mReceiveBuffer.limit();
          byte[] mMessageBuffer = new byte[mSize];
          mReceiveBuffer.get(mMessageBuffer);
          final String message = mRemoteAddress+":\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);
           }
          });
          //
         }
        }
        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_Client","The selector selects fail.");
      }
     }
     
     //close channel and selector
     try 
     {
      mClientChannel.keyFor(mSelector).cancel();
      mClientChannel.disconnect();
      mClientChannel.socket().close();
      mClientChannel.close();
      mSelector.close();
      mSelector = null;
      mClientChannel = null;
     } 
     catch (IOException e) 
     {
      // TODO Auto-generated catch block
      e.printStackTrace();
      Log.e("NIOUDP_Client","Close channel fail.");
     }
     //
    } 
    catch(ClosedChannelException c)
    {
     c.printStackTrace();
     Log.e("NIOUDP_Client","Channel registering fail.");
     isRunning = false;
     return;
    }
    //
  }
 };
 //
 
 //send the message
 private Runnable sendMessageProcess = new Runnable()
  {
   @Override
   public void run() 
   {
    try 
    {
     ByteBuffer mSendBuffer = ByteBuffer.allocate(MAX_PACKET_SIZE);
     mSendBuffer.put(send_message.getBytes());
     mSendBuffer.flip();

     int size = mClientChannel.send(mSendBuffer, mRemoteAddress);
     if(size == 0)
     {
      mClientChannel.keyFor(mSelector).interestOps( mClientChannel.keyFor(mSelector).interestOps() ^ SelectionKey.OP_WRITE);
      Log.e("NIOUDP_Client","ByteBuffer is full.");
     }
    } 
    catch (IOException e)
    {
    // TODO Auto-generated catch block
    e.printStackTrace();
    Log.e("NIOUDP_Client","Channel is already closed.");
    }
   }
 };
 //
}

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

    <EditText
        android:id="@+id/xml_etIP"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_toLeftOf="@+id/xml_btStartOrClose"
        android:ems="10"
        android:inputType="text" />

    <TextView
        android:id="@+id/xml_tvIP"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/xml_etIP"
        android:layout_alignParentLeft="true"
        android:text="IP:"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <Button
        android:id="@+id/xml_btStartOrClose"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:text="Start" />

    <TextView
        android:id="@+id/xml_tvPort"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/xml_btStartOrClose"
        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_alignBottom="@+id/xml_tvPort"
        android:layout_alignRight="@+id/xml_etIP"
        android:layout_toRightOf="@+id/xml_tvPort"
        android:ems="10"
        android:inputType="number"
        android:minEms="5" >

        <requestFocus />
    </EditText>

    <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_centerVertical="true"
        android:lines="8"
        android:maxLines="8"
        android:text="Waiting for connecting..."
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <EditText
        android:id="@+id/xml_etMessage"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_toLeftOf="@+id/xml_btStartOrClose"
        android:ems="10"
        android:inputType="textMultiLine" />

    <Button
        android:id="@+id/xml_btSend"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:text="Send" />

</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>

沒有留言 :

張貼留言