[轉貼]Android開發之Socket編程
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();
}
}
}
運行結果:
界面
點擊「啟動服務器端監聽」按鈕,然後執行TCPClient.java,控制台輸出接收到的數據
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,控制台輸出接收到的數據


0 Responses to "[轉貼]Android開發之Socket編程"
留下您的意見: