2013年4月19日 星期五

[Android] 手機資料傳到電腦(WiFi)

如何將手機資料經由WIFI傳到電腦呢?
我們可以利用ServerSocket(Server端)和socket(Client端)來實作一個例子
從手機裡選一張照片傳送到電腦,
這裡有一點要注意,Server和client需在同一個網址。

電腦端(Server):
先自訂一個port(這裡是設成1111), 然後new一個ServcerSocket,
再呼叫accept()方法,這個方法會一直等到client端連進來,
才會執行下一行程式。

這邊的build法,我是用eclipse,直接NEW->Java project,打入程式後,
直接按RUN(Ctrl+F11)去執行,然後等待Android端連進來。

DesktopServerTCP.java
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class DesktopServerTCP implements Runnable {

 public static final int SERVERPORT = 1111;

 // 最後要儲存照片的位置
 public static final String file_name = "C:\\Users\\Public\\Pictures\\Sample Pictures\\test.jpeg";

 public void run() {

  try {

   System.out.println("Server: Connecting...");
   ServerSocket serverSocket = new ServerSocket(SERVERPORT);

   while (true) {

    Socket client = serverSocket.accept();
    System.out.println("Server: Receiving...");

    OutputStream out = new FileOutputStream(file_name);
    byte buf[] = new byte[1024];
    int len;

    // 讀入從手機端傳來的照片
    InputStream inputStream = client.getInputStream();
    try {
     while ((len = inputStream.read(buf)) != -1) {
      // 將照片寫入到電腦裡
      out.write(buf, 0, len);
     }
     out.close();
     inputStream.close();

    } catch (IOException e) {
     e.printStackTrace();
    } finally {

     client.close();
     System.out.println("Server: Done.");

    }

   }

  } catch (Exception e) {

   System.out.println("Server: Error");
   e.printStackTrace();

  }

 }

 public static void main(String str[]) {

  Thread desktopSerThread = new Thread(new DesktopServerTCP());
  desktopSerThread.start();

 }
}

Android端(Client):
這邊我設計成,程式一啟動,就選一張照片傳送到電腦端,
分成二個階段:
第一個階段時,new一個socket,然後帶入Server端的IP位址及Port number,
第二個階段,先將照片讀入後,存在buffer裡,
然後在利用outputstream輸出至Server端。

MainActivity.java
package com.example.socketclient;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends Activity {

 Socket socket;
 //從手機裡的"我的檔案"選張照片,準備傳到電腦,
 //因不同的手機路徑可能不同,可自行修改。
 public static final String file_name = "//storage//sdcard0//Download//images.jpeg";

 @Override
 public void onCreate(Bundle savedInstanceState) {

  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  Thread test = new Thread(clientSocket);
  test.start();

 }

 Runnable clientSocket = new Runnable() {

  @Override
  public void run() {

   try {

    InetAddress serverAddr = InetAddress.getByName("192.168.1.104");
    Log.e("Socket", "Client: Connecting...");

    try {

     socket = new Socket(serverAddr, 1111);
     OutputStream outputstream = socket.getOutputStream();

     File myFile = new File(file_name);

     if (myFile.exists()) {

      byte[] mybytearray = new byte[(int) myFile.length()];
      FileInputStream fis = new FileInputStream(myFile);

      BufferedInputStream bis = new BufferedInputStream(fis,
        8 * 1024);
      bis.read(mybytearray, 0, mybytearray.length);
      //輸出到電腦
      outputstream.write(mybytearray, 0, mybytearray.length);
      outputstream.flush();

     } else
      Log.e("Socket", "file doesn't exist!");

    } catch (Exception e) {

     Log.e("Socket", "Client: Error", e);

    } finally {

     socket.close();

    }
   } catch (Exception e) {

   }

  }

 };

}

最後,因為我們有用到網路傳輸,
所以記得在xml加入INTERNET,和讀取SD卡的的權限。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.socketclient"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.socketclient.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>
   <uses-permission android:name="android.permission.INTERNET" /> 
  <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 
    </manifest>

28 則留言:

  1. 你好,若是我只想傳送一個值讓伺服器在output顯示,是否也要使用outputstream write呢 ?
    試了好久都沒有合式的傳出值語法

    回覆刪除
  2. 如果是要傳到伺服器,這個網站有個例子,
    希望對你有幫助
    http://j796160836.pixnet.net/blog/post/28994669

    回覆刪除
  3. 不好意思,我試傳了好幾次都是空白檔案,這樣是不是失敗了?

    回覆刪除
    回覆
    1. 我猜應該是路徑有錯,要改成你手機裡放照片的路徑,String file_name = "//storage//sdcard0//Download//images.jpeg";
      然後在檢查outputstream.write(mybytearray, 0, mybytearray.length); 裡的mybytearray有沒有值,如果是空的,就很可能是路徑錯了,

      刪除
  4. 對不起,耍笨了
    我把'o'打成'u' = =
    謝謝你^^

    回覆刪除
  5. 我想請問如果要用手機發送出一個值給wifi模組!!請問指令該怎麼做?資料是經由RS232傳送

    回覆刪除
    回覆
    1. 您是指從手機的RS232發出一個值給另一WIFI模組?

      刪除
  6. 可以請問一下 同個網址是什麼意思嗎?

    回覆刪除
    回覆
    1. 您好, 是指你的電腦端和手機要連上同一個WIFI AP

      刪除
    2. OKOK~ 非常感謝您

      刪除
  7. 大大您好,我想請問一個問題
    目前我測試Server跟Client都在同台電腦下可以連接,在不同電腦間也可以連接
    但我把APP實裝在手機上後,就不行了,Server端完全收不到連線要求(電腦跟手機是在同個網址下)
    可以請問大大有遇過這樣的問題嗎??

    感謝您

    回覆刪除
  8. 大大您好我才剛寫android沒有很久但是最近有寫出一個APP是關於手機連接wifi模組(RM04)傳送命令!!但是APP程式IP跟port都和wifi模組(RM04)對照過了!!程式上也不知道是出什麼問題想請問大大是什麼原因還有哪裡沒注意到!!!可以的話方便我用信箱傳程式碼給你看嗎?才剛踏入沒多久有許多專業用詞不大懂!!麻煩大大指教了

    回覆刪除
  9. OK, 你寄給我, 我週未幫你看看^^ chenkanzo@gmail.com

    回覆刪除
    回覆
    1. 大大您好!!程式我已經加壓縮傳給你了!!麻煩你抽空幫我看看

      刪除
  10. 請問
    InetAddress serverAddr = InetAddress.getByName("192.168.39.60");
    我這行出現Unhandled exception: java.net.UnknownHostException錯誤
    苦苦不知什麼意思

    回覆刪除
  11. 我猜有幾個地方可以看看,
    1) 要用try catch把這行包起來
    2) 192.168.39.60這個位址有錯嗎?
    3) 有在AndroidManifest.xml 加入權限嗎

    回覆刪除
  12. 大大您好,想請問一下
    public static final String file_name = "//storage//sdcard0//Download//images.jpeg";
    這句話的意思是會跳出挑選照片的視窗? 還是只能傳特定一張,每次都要改不同檔名?
    如果是後者 那不就每次都需要重新匯出app然後再安裝?

    回覆刪除
  13. 那一行是圖的路徑, 看你的圖片放在手機哪裡,就改成那個路徑, 這個例子單純是重WIFI傳圖片到PC, 其它功能要自己實作喔

    回覆刪除
  14. 大大你好
    如果想改用udp的方式該怎麼改比較好???
    想試試傳輸影片

    回覆刪除
    回覆
    1. 可參考 http://www.cs.uic.edu/~troy/spring05/cs450/sockets/socket.html裡的UDPClient.java和UDPServer.java

      刪除
  15. 您好我想請問那如果是電腦再丟值給手機呢?

    回覆刪除
  16. 大大您好: 請問我用arduino模組(wifi)傳送一串 telnet訊息!!
    請問我將如何以Andrino手機接收顯示呢??
    請問與您的範例有類似嗎??

    回覆刪除
  17. 想問是否能讓兩邊的檔名相同

    回覆刪除
  18. 請問電腦端的程式是用甚麼軟體編譯

    回覆刪除
  19. 作者已經移除這則留言。

    回覆刪除