Android - Socket 編程(WIFI 和 ADB)


昨天正式開始 Android 編程學習與實踐,由於 Android 模擬器在 WinXP 下一直未安裝成功(見帖子: http://www.cnblogs.com/91program/p/5190888.html),所在將閑置很久的 Android 手機: 聯想 A750 找到用於調試。
A750 是 Android 版本是: 2.3.6,在手機 上打開 USB 調試功能后,就可以通過 USB 線與 PC 連接進行調試了。
調試的主要功能是 Socket 通訊,手機做為服務器端。先用 PC 做為客戶端。后期的客戶端是車機,車機的系統可能是 WinCE 或 Android。
開始之前,先了解了一下 Android 編程的基本知識(后附個人學習記錄的知識點),然后學習了如下鏈接:http://www.cnblogs.com/lknlfy/archive/2012/03/04/2379628.html 關於 Socket 編程的知識。

其中 一個關鍵的知識點是線程與主進程之間的消息傳遞機制,主要是線程中的消息傳遞到主進程。例如:

mHandler.sendMessage(msg); 

手機端代碼如下(XML就不提供了,很簡單,大家看圖就知識的):
/*
 * 通過  WIFI 網絡進行 Socket 通訊成功, 手機的 IP: 172.25.103.4(隨個人網絡環境變化)
 * 測試使用 360 隨身 WIFI, PC 機的 IP: 172.25.103.1
 * */

  1 package com.jia.leozhengfirstapp;
  2 
  3 
  4 import java.io.IOException;
  5 import java.io.InputStream;
  6 import java.io.UnsupportedEncodingException;
  7 import java.net.ServerSocket;
  8 import java.net.Socket;
  9 
 10 
 11 import android.support.v7.app.ActionBarActivity;
 12 import android.annotation.SuppressLint;
 13 import android.os.Bundle;
 14 import android.os.Handler;
 15 import android.os.Message;
 16 import android.util.Log;
 17 import android.view.Menu;
 18 import android.view.MenuItem;
 19 import android.widget.TextView;
 20 import android.widget.Toast;
 21 
 22 
 23 
 24 
 25 public class MainActivity extends ActionBarActivity {
 26 
 27 
 28     private Socket clientSocket = null;
 29     private ServerSocket mServerSocket = null;
 30 
 31 
 32     private Handler mHandler = null;
 33 
 34 
 35     private AcceptThread mAcceptThread = null;
 36     private ReceiveThread mReceiveThread = null;
 37     private boolean stop = true;
 38 
 39     private TextView ipText;
 40     private TextView rcvText;
 41     private TextView ConnectStatusText;
 42 
 43     @SuppressLint("HandlerLeak")
 44     @Override
 45     protected void onCreate(Bundle savedInstanceState) {
 46         super.onCreate(savedInstanceState);
 47         setContentView(R.layout.activity_main);
 48 
 49         ipText = (TextView)findViewById(R.id.textView1);
 50         rcvText = (TextView)findViewById(R.id.textView3);
 51         ConnectStatusText = (TextView)findViewById(R.id.textView4);
 52 
 53         ConnectStatusText.setText("連接狀態: 未連接");
 54 
 55         // 消息處理
 56         mHandler = new Handler()
 57         {
 58             @Override
 59             public void handleMessage(Message msg)
 60             {
 61                 switch(msg.what)
 62                 {
 63                     case 0:
 64                     {
 65                         String strAddress = (msg.obj).toString();
 66                         ipText.setText("IP地址: " + strAddress);
 67                         Log.v("Leo: IP: ", strAddress);
 68                         ConnectStatusText.setText("連接狀態: 已連接");
 69                         // 顯示客戶端IP
 70                         // ipTextView.setText((msg.obj).toString());
 71                         // 使能發送按鈕
 72                         // sendButton.setEnabled(true);
 73                         break;
 74                     }
 75                     case 1:
 76                     {
 77                         String strRcv = (msg.obj).toString();
 78                         rcvText.setText("接收到數據: " + strRcv);
 79                         Log.v("Leo: Rcv: ", strRcv);
 80                         // 顯示接收到的數據
 81                         // mTextView.setText((msg.obj).toString());
 82                         break;
 83                     }
 84                 }
 85 
 86             }
 87         };
 88 
 89         mAcceptThread = new AcceptThread();
 90         // 開啟監聽線程
 91         mAcceptThread.start();
 92     }
 93 
 94 
 95 
 96 
 97     @Override
 98     public boolean onCreateOptionsMenu(Menu menu) {
 99         // Inflate the menu; this adds items to the action bar if it is present.
100         getMenuInflater().inflate(R.menu.main, menu);
101         return true;
102     }
103 
104 
105     @Override
106     public boolean onOptionsItemSelected(MenuItem item) {
107         // Handle action bar item clicks here. The action bar will
108         // automatically handle clicks on the Home/Up button, so long
109         // as you specify a parent activity in AndroidManifest.xml.
110         int id = item.getItemId();
111         if (id == R.id.action_settings) {
112             return true;
113         }
114         return super.onOptionsItemSelected(item);
115     }
116 
117     // 顯示Toast函數
118     private void displayToast(String s)
119     {
120         Toast.makeText(this, s, Toast.LENGTH_SHORT).show();
121     }
122 
123     private class AcceptThread extends Thread
124     {
125         @Override
126         public void run()
127         {
128             try {
129                 // 實例化ServerSocket對象並設置端口號為 12589
130                 mServerSocket = new ServerSocket(12589);
131             } catch (IOException e) {
132                 // TODO Auto-generated catch block
133                 e.printStackTrace();
134             }
135 
136             try {
137                 // 等待客戶端的連接(阻塞)
138                 clientSocket = mServerSocket.accept();
139             } catch (IOException e) {
140                 // TODO Auto-generated catch block
141                 e.printStackTrace();
142             }
143 
144             mReceiveThread = new ReceiveThread(clientSocket);
145             stop = false;
146             // 開啟接收線程
147             mReceiveThread.start();
148 
149             Message msg = new Message();
150             msg.what = 0;
151             // 獲取客戶端IP
152             msg.obj = clientSocket.getInetAddress().getHostAddress();
153             // 發送消息
154             mHandler.sendMessage(msg);
155         }
156     }
157 
158 
159 
160 
161     private class ReceiveThread extends Thread
162     {
163         private InputStream mInputStream = null;
164         private byte[] buf;
165         private String str = null;
166 
167         ReceiveThread(Socket s)
168         {
169             try {
170                 // 獲得輸入流
171                 this.mInputStream = s.getInputStream();
172             } catch (IOException e) {
173                 // TODO Auto-generated catch block
174                 e.printStackTrace();
175             }
176         }
177 
178         @Override
179         public void run()
180         {
181             while(!stop)
182             {
183                 this.buf = new byte[512];
184 
185                 // 讀取輸入的數據(阻塞讀)
186                 try {
187                     this.mInputStream.read(buf);
188                 } catch (IOException e1) {
189                     // TODO Auto-generated catch block
190                     e1.printStackTrace();
191                 }
192 
193                 // 字符編碼轉換
194                 try {
195                     this.str = new String(this.buf, "GB2312").trim();
196                 } catch (UnsupportedEncodingException e) {
197                     // TODO Auto-generated catch block
198                     e.printStackTrace();
199                 }
200 
201                 Message msg = new Message();
202                 msg.what = 1;
203                 msg.obj = this.str;
204                 // 發送消息
205                 mHandler.sendMessage(msg);
206             }
207         }
208     }
209 }

1) 先通過 WIFI 進行 Socket 通訊
運行后,在手機上顯示的未連接界面如下圖:

在 PC 上運行類似於 SocketTool.exe 的工具,SocketTool.exe 的顯示界面如下:

Socket 連接后,手機上顯示的界面如下圖:

2) 通過 USB 實現 PC 與手機的通訊
在 PC 上實現一個 Java 小應用,應用的主要代碼如下:

 1 try
 2 {
 3     Runtime.getRuntime().exec("adb forward tcp:12581 tcp:12589");
 4 }
 5 catch (IOException e)
 6 {
 7     e.printStackTrace();
 8 }
 9 
10 
11 Socket socket = null;
12 try
13 {
14     InetAddress serverAddr = null;
15     OutputStream outStream = null;
16     byte[] msgBuffer = null;
17 
18     serverAddr = InetAddress.getByName("127.0.0.1");
19     System.out.println("TCP 1" + "C: Connecting...");
20 
21 
22     socket = new Socket(serverAddr, 12581); // 12581 是 PC 的端口,已重定向到 Device 的 12589 端口
23 
24     String message = "PC ADB,send message";
25     msgBuffer = message.getBytes("GB2312");
26 
27     outStream = socket.getOutputStream();
28     outStream.write(msgBuffer);
29     Thread.sleep(10000);
30 }
31 catch (UnknownHostException e1)
32 {
33     System.out.println("TCP 2" + "ERROR: " + e1.toString());
34 }
35 catch (IOException e2)
36 {
37     System.out.println("TCP 3" + "ERROR: " + e2.toString());
38 } catch (InterruptedException e3)
39 {
40     // Thread.sleep(1000); 增加的異常處理
41     e3.printStackTrace();
42 }
43 finally
44 {
45     try
46     {
47         if (socket != null)
48         {
49             socket.close();     // 關閉時會導致接收到的數據被清空,所以延時 10 秒顯示
50         }
51     }
52     catch (IOException e)
53     {
54         System.out.println("TCP 4" + "ERROR: " + e.toString());
55     }
56 }

運行后,在手機上顯示的界面如下圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM