Home > > [轉貼]Android開發之Socket編程

[轉貼]Android開發之Socket編程

2011年11月15日星期二

Socket簡介

      Socket(套接字)是一種抽像層,應用程序通過它來發送和接收數據,就像應用程序打開了一個文件句柄,將數據讀寫到穩定的存儲器上一樣。使用Socket可以將應用程序添加到網絡中,並與處於同一網絡中的其他應用程序進行通信。一台計算機上的應用程序向socket寫入的信息能夠被另一台計算機上的另一個應用程序讀取,反之依然。根據不同的的底層協議實現,也會很多種不同的Socket。本課當中只覆蓋了TCP/IP協議族的內容,在這個協議族當中主要的Socket類型為流套接字(stream socket)和數據報套接字(datagram socket)。流套接字將TCP作為其端對端協議,提供了一個可信賴的字節流服務。數據報套接字使用UDP協議,提供可一個「盡力而為」的數據報服務,應用程序可以通過它發送最長65500字節的個人信息。
使用基於TCP協議的Socket
一個客戶端要發起一次通信,首先必須知道運行服務器端的主機IP地址。然後由網絡基礎設施利用目標地址,將客戶端發送的信息傳遞到正確的主機上,在Java中,地址可以由一個字符串來定義,這個字符串可以使數字型的地址(比如192.168.1.1),也可以是主機名(example.com)。
在Java當中InetAddress類代表了一個網絡目標地址,包括主機名和數字類型的地址信息。下面為大家介紹一下基於TCP協議操作Socket的API:
ServerSocket:這個類是實現了一個服務器端的Socket,利用這個類可以監聽來自網絡的請求。
a) 創建ServerSocket的方法:
ServerSocket(Int localPort)
ServerSocket(int localport,int queueLimit)
ServerSocket(int localport,int queueLimit,InetAddress localAddr)
創建一個ServerSocket必須指定一個端口,以便客戶端能夠向該端口號發送連接請求。端口的有效範圍是0-65535
b) ServerSocket操作
Socket accept()
void close
accept()方法為下一個傳入的連接請求創建Socket實例,並將已成功連接的Socket實例返回給服務器套接字,如果沒有連接請求,accept()方法將阻塞等待;
close方法用於關閉套接字
Socket:
a) 創建Socket的方法:
Socket(InetAddress remoteAddress,int remotePort)
利用Socket的構造函數,可以創建一個TCP套接字後,先連接到指定的遠程地址和端口號。
b) 操作Socket的方法
InputStream getInputStream()
OutputStream getOutputStream()
void close()
使用基於UDP的Socket
a) 創建DatagramPacket
DatagramSocket(byte [] data,int offset,int length,InetAddress remoteAddr,int remotePort)
該構造函數創建一個數據報文對象,數據包含在第一個參數當中
b) 創建DatagramSocket創建
DatagramSocket(int localPort)
以上構造函數將創建一個UDP套接字;
c) DatagramSocket:發送和接受
void send(DatagramPacket packet)
void receive(DatagramPacket packet)
send()方法用來發送DatagramPacket實例。一旦創建連接,數據報將發送到該套接字所連接的地址;
receive()方法將阻塞等待,知道接收到數據報文,並將報文中的數據複製到指定的DatagramPacket實例中

Android 模擬器中做端口重定向

       開發的過程中遇到一個問題:android的模擬器有個特點,就是訪問網絡的時候只可以從模擬器主動往出去連。但是卻無法主的從外面連接模擬器,這個特點和NAT幾乎完全一樣,具有單向連接的特性。 實際開發中我們希望模擬器像一台獨立的手機一樣,能和處於同一局域網中的手機進行端對端的通信。這時就需要做端口重定向。 類似於給路由器做nat的端口重定向。下面幾步: >運行模擬器:你會發現模擬器標題欄上寫著端口號:5554,其實這個端口號是模擬器的console端口 >telnet到模擬器的console口上:telnet localhost 5554 (如果你用的是win7. 默認是沒有開啟telnet功能的,開啟的方法看這裡http://hi.baidu.com/lzhts/blog/item/2442d162a0c618cfe6113ae2.html) >在控制台下輸入 redir add tcp:6668:9998 就完成了從主機6668端口重定向到模擬器9998端口的任務。

重定向tcp端口:redir add tcp:6668:9998

重定向udp端口:redir  add udp:6668:9998

刪除重定向tcp端口:redir del tcp:6668

刪除重定向udp端口:redir del udp:6668

查看重定向列表:redir list

TCP協議編程示例:

       新建一個Android應用程序作為Socket通信的服務器端。重定向tcp端口:redir add tcp:6661:6661

      main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/hello"
    />
<Button
    android:id="@+id/buttonStart"
    android:layout_width="300dp"
    android:layout_height="wrap_content"
    android:text="啟動服務器端監聽"
    />
</LinearLayout>

 

Android_Socket.java

 

package idea.org;

import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class Android_Socket extends Activity {
    private Button buttonStart=null;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        buttonStart=(Button)findViewById(R.id.buttonStart);
        buttonStart.setOnClickListener(new buttonListener());
    }
    class buttonListener implements OnClickListener
    {
    /* (non-Javadoc)
     * @see android.view.View.OnClickListener#onClick(android.view.View)
     */
    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub
        new Thread()
        {

            /* (non-Javadoc)
             * @see java.lang.Thread#run()
             */
            @Override
            public void run() {
                // TODO Auto-generated method stub
                ServerSocket serverSocket=null;
                try
                {
                              //創建ServerSocket對像監聽6661端口
                    serverSocket=new ServerSocket(6661);
                              //接收tcp連接返回socket對像
                    Socket socket=serverSocket.accept();
                              //獲得輸入流
                    InputStream inputStream=socket.getInputStream();                   
                    byte []byteBuffer=new byte[1024];
                    int temp=0;
                              //讀取接收的數據
                    while((temp=inputStream.read(byteBuffer))!=-1)
                        System.out.println(new String(byteBuffer,0,temp));
                    socket.close();
                    serverSocket.close();
                   
                }
                catch(IOException e)
                {
                    e.printStackTrace();
                }
            }
           
        }.start();
    }
   };
}

 

   AndroidManifest.xml

 

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="idea.org"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="11" />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".Android_Socket"
                  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>
    <uses-permission android:name="android.permission.INTERNET"/>   
</manifest>

 

新建一個java程序作為客戶端。

      TCPClient.java

 

package idea.org;

import java.io.FileInputStream;
import java.io.InputStream;
import java.net.Socket;

public class TCPCient {
    public static void main(String[] args)
    {
        try {
            //定義Socket對象,連接指定IP和指定端口
            Socket socket=new Socket("127.0.0.1",6661);
            InputStream inputStream=new FileInputStream("F://test.txt");
            //從Socket對像獲得輸出流
            java.io.OutputStream outputStream=socket.getOutputStream();
            int temp=0;
            byte[]buffer=new byte[1024];
            //向輸出流中寫要發送的數據
            while((temp=inputStream.read(buffer))!=-1)
            {           
                outputStream.write(buffer,0,temp);
                System.out.println(new String(buffer,0,temp));
            }
            outputStream.flush();       
            socket.close();
        }
        catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }       
    }
}

 

運行結果:

      界面

image

      點擊「啟動服務器端監聽」按鈕,然後執行TCPClient.java,控制台輸出接收到的數據

 

image

 

UDP協議編程示例

      重定udp端口:redir add udp:6662:6662

      將上面示例中的Android_Socket.java換成如下代碼即可。

      Android_Socket.java

 

package idea.org;

import java.io.IOException;
import java.io.InputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class Android_Socket extends Activity {
    private Button buttonStart=null;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        buttonStart=(Button)findViewById(R.id.buttonStart);
        buttonStart.setOnClickListener(new buttonListener());
    }
    class buttonListener implements OnClickListener
    {
    /* (non-Javadoc)
     * @see android.view.View.OnClickListener#onClick(android.view.View)
     */
    @Override
    public void onClick(View arg0) {
        // TODO Auto-generated method stub
        new Thread()
        {

            /* (non-Javadoc)
             * @see java.lang.Thread#run()
             */
            @Override       
            public void run() {
                // TODO Auto-generated method stub               
                try
                {
                    //創建一個DatagramSocket對象並指定監聽的端口
                    DatagramSocket socket=new DatagramSocket(6662);
                    byte[]data=new byte[1024];
                    //創建一個空的DatagramPacket對像用來存放接收到的DatagramPacket
                    DatagramPacket packet=new DatagramPacket(data,data.length);
                    //使用receive方法接收客戶端發送的數據
                    socket.receive(packet);                   
                    String result=new String(packet.getData(),packet.getOffset(),packet.getLength());
                    System.out.println(result);
                }
                catch(IOException e)
                {
                    e.printStackTrace();
                }
            }
           
        }.start();
    }
   };
}

新建一個java程序作為客戶端。

     UDPClient.java

 

package idea.org;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

public class UDPClient {
    public static void main(String []args)
    {
        try
        {
            //創建一個DatagramSocket對像
            DatagramSocket socket=new DatagramSocket();
            //創建一個表示IP地址的InetAddress對像
            InetAddress serverAddress=InetAddress.getByName("192.168.0.5");
            String str="Hello,world!Hello,Everyone!";
            byte[]data=str.getBytes();
            //創建一個用於發送的DatagramPacket對像
            DatagramPacket packet=new DatagramPacket(data,data.length,serverAddress,6662);
            //發送數據
            socket.send(packet);
        }
        catch(Exception e)
        {
            e.printStackTrace();

        }
    }

}

 

     點擊「啟動服務器端監聽」按鈕,然後執行UDPClient.java,控制台輸出接收到的數據

image

 

http://gcgmh.iteye.com/blog/288578

0 Responses to "[轉貼]Android開發之Socket編程"