[Android開発]Wi-Fi Directでファイル送信をしよう②

2018年11月23日

スポンサーリンク

前回は、Wi-Fi Directを利用して
サーバーとクライアントに分けてファイル送信を行ったが,
前回のソースコードでは片方にしかファイルを送信できない問題があった。

なので今回は,相互間でファイルのやり取りを行う方法について検討してみた.

なお、今回のソースコードは、先にWi-Fi Diretのグループオーナー端末が
子からファイルを受け取る事で、クライアントのIPを取得する方法で実装している。

クライアントの情報を、最初から取得する方法があるだろうが
今回はその解を見つけることは出来なかった。

では,実際のソースコードを見ていこう.

まず,今回はサーバーとクライアントのファイル構造を分けて
ソース記述しているので、全部のソースコードを
一度載る
まずMainActivityの処理(ボタンは各自配置しください,またimportはWi-FiDirect利用するための処理も残っているので各自で調整を).
また,ハンドラー処理はメッセージをトーストで通知するためだけのものなので
取り除いてしまっても結構です.

import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Color;
import android.net.NetworkInfo;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pGroup;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
// Handlerのステータス
public static final int Server_Start = 1;
public static final int File_Recive = 2;
public static final int File_Send = 3;
public static final int File_Send_Success = 4;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Wi-Fi Direct スタート
Button wifistart = (Button) findViewById(R.id.wd_start);
wifistart.setOnClickListener(new WDStart());
//ファイルを送る
Button FileSend = (Button) findViewById(R.id.FileSend);
FileSend.setOnClickListener(new FileSend());
//ファイルを受信
Button FileRecive = (Button) findViewById(R.id.FileRecive);
FileRecive.setOnClickListener(new FileRecive());
}
//ファイルを送る処理
class FileSend implements View.OnClickListener {
// onClickメソッド(ボタンクリック時イベントハンドラ)
public void onClick(View v) {
//クライアントの呼び出し
Client client = new Client(mHandler);
new Thread(client).start();
}
}
//サーバーの起動
class FileRecive implements View.OnClickListener {
// onClickメソッド(ボタンクリック時イベントハンドラ)
public void onClick(View v) {
Server server = new Server(mHandler);
new Thread(server).start();
}
}
//トーストをサーバーとかから呼び出す処理
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case Server_Start:
Toast.makeText(MainActivity.this, "ServerStart", Toast.LENGTH_SHORT).show();
break;
case File_Recive:
Toast.makeText(MainActivity.this, "FileRecive", Toast.LENGTH_SHORT).show();
break;
case File_Send:
Toast.makeText(MainActivity.this, "FileSend", Toast.LENGTH_SHORT).show();
break;
case File_Send_Success:
Toast.makeText(MainActivity.this, "FileSendSuccess", Toast.LENGTH_SHORT).show();
break;
}
}
};
}

次にサーバとクライアント処理です。
こちらはトースト機能を取り除けばそのままコピペで使えると思います.

パッケージも各自変更を宜しくお願いします
まずはサーバ側

import android.os.Environment;
import android.os.Handler;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import static com.sonitan.wdfilesend003.Client.HOST;
public class Server implements Runnable {
final static int PORT = 8001;    // 待受ポート番号
//受信したファイルの保存先
String path02 = Environment.getExternalStorageDirectory().getPath() + "/Download/reciveresult.txt";
private Handler mHandler;
//インスタンス
public Server(Handler handler) {
mHandler = handler;
}
@Override
public void run() {
String outputFilepath = path02;       // 受信したファイルの保存先
byte[] buffer = new byte[512]; // ファイル受信時のバッファ
//メッセージ
mHandler.obtainMessage(MainActivity.Server_Start, 0, 0, null).sendToTarget();
try {
// ソケットの準備
ServerSocket serverSocket = new ServerSocket(PORT);
Socket socket = serverSocket.accept();
//相手のIPアドレスを取得
String address = socket.getInetAddress().getHostAddress();
//ClientのHostのIPアドレスを変更する
HOST = address;
// ストリームの準備
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = new FileOutputStream(outputFilepath);
// ファイルをストリームで受信
int fileLength;
while ((fileLength = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, fileLength);
}
// 終了処理
outputStream.flush();
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
//サーバの再起動
Server ss = new Server(mHandler);
ss.run();
} catch (IOException e) {
e.printStackTrace();
}
}
}

次にクライアント

import android.os.Environment;
import android.os.Handler;
import android.util.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class Client implements Runnable {
final static int    PORT = 8001;        // 接続先ポート番号
static String HOST = "192.168.49.1"; // 接続先アドレス
private Handler mHandler;             //メッセージを送るよう
//送信するファイルのパス
String path = Environment.getExternalStorageDirectory().getPath()+"/Download/test100kb.txt";
//インスタンス
public Client(Handler handler) {
mHandler = handler;
}
//ファイルを送信する処理
@Override
public void run() {
File file     = new File(path); // 送信するファイルのオブジェクト
byte[] buffer   = new byte[512];      // ファイル送信時のバッファ
//メッセージ
mHandler.obtainMessage(MainActivity.File_Send, 0, 0, null).sendToTarget();
try {
// ソケットの準備
Socket socket = new Socket(HOST, PORT);
// ストリームの準備
InputStream inputStream  = new FileInputStream(file);
OutputStream outputStream = socket.getOutputStream();
// ファイルをストリームで送信
int fileLength;
while ((fileLength = inputStream.read(buffer)) > 0) {
outputStream.write(buffer, 0, fileLength);
}
// 終了処理
outputStream.flush();
outputStream.close();
inputStream.close();
//ソケットを閉じる
socket.close();
//メッセージ送信
mHandler.obtainMessage(MainActivity.File_Send_Success, 0, 0, null).sendToTarget();
} catch (IOException e) {
e.printStackTrace();
Log.d("ファイル送信","失敗" +e.toString());
}
}
}

では変更点を見ていこう!

今回は、サーバは一度クライアントよりファイルを送られてきた場合
クライアントのIPアドレスを、取得してHOSTに格納している.

 //相手のIPアドレスを取得
String address = socket.getInetAddress().getHostAddress();
//ClientのHostのIPアドレスを変更する
HOST = address;

この処理により、最初にサーバとなっている端末が
クライアント端末よりファイルを一度受け取った後は相互通信が可能になっているというわけだ.

スポンサーリンク