質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

Q&A

解決済

1回答

11131閲覧

2台のアンドロイドスマホでソケット通信の使い方を教えてください。

H30_inenaga

総合スコア18

Android Studio

Android Studioは、 Google社によって開発された、 Androidのネイティブアプリケーション開発に特化した統合開発ツールです。

0グッド

1クリップ

投稿2018/10/15 04:31

編集2018/10/16 03:18

###解決したいこと
ソケット通信のプログラミングを、AndroidStudioにて終えました。
無事、ビルドもランもできています。

ただ、私、通信の知識に疎いので、これから通信に関して色々とお聞きしたいことがあります。
手始めとして、ソケット通信を2台のスマホで行うためには、IPアドレスと、ポート番号は何番を入力すればよいのでしょうか?
※ちなみに自前のWifiルータを使用していますが、携帯回線(wifiルータなし)でも通信できるのでしょうか?

[1]「設定」の歯車アイコンをタップ→無線とネットワークの項目から「Wi-Fi」をタップ→右上にある歯車アイコンをタップ→IPアドレス
[2]https://www.cman.jp/network/support/go_access.cgi

[1]で行って確認するIPアドレスと、[2]で行うIPアドレスが違うのですが、なぜなのでしょうか?
あと、実行すると、Runはできているが、通信失敗しました2というメッセージが表示されます。
通信失敗しました2というのはソースコードをご覧いただければ幸いです。

以下にソースコードを掲載します。//ここを教えてください というコメントが2点ございますので先の疑問点とともに指摘いただければ幸いです。
###ソースコード

java

1import android.app.Activity; 2import android.graphics.Color; 3import android.os.Bundle; 4import android.os.Handler; 5import android.view.View; 6import android.view.ViewGroup; 7import android.view.Window; 8import android.widget.Button; 9import android.widget.EditText; 10import android.widget.LinearLayout; 11import android.widget.TextView; 12 13import java.io.InputStream; 14import java.io.OutputStream; 15import java.net.Socket; 16 17//ソケット通信 18public class MainActivity extends Activity 19 implements View.OnClickListener{ 20 private final static String BR = System.getProperty("line.separator"); 21 private final static int WC = ViewGroup.LayoutParams.WRAP_CONTENT; 22 private final static int MP = ViewGroup.LayoutParams.MATCH_PARENT; 23 24 //IPアドレスの指定 25 private final static String IP = "000.000.000.000";//変更必須 26 27 private TextView lblReceive; //受信ラベル 28 private EditText edtSend; //送信エディットテキスト 29 private Button btnSend; //送信ボタン 30 31 private Socket socket ; //ソケット 32 private InputStream in; //入力ストリーム 33 private OutputStream out; //出力ストリーム 34 private boolean error; //エラー 35 36 private final Handler handler = new Handler();//ハンドラ 37 38 //アクティビティ起動時に呼ばれる 39 @Override 40 public void onCreate(Bundle bundle) { 41 super.onCreate(bundle); 42 requestWindowFeature(Window.FEATURE_NO_TITLE); 43 44 //レイアウトの生成 45 LinearLayout layout = new LinearLayout(this); 46 layout.setBackgroundColor(Color.BLACK); 47 layout.setOrientation(LinearLayout.VERTICAL); 48 setContentView(layout); 49 50 //送信エディトテキストの生成 51 edtSend = new EditText(this) ; 52 edtSend.setText(""); 53 edtSend.setOnClickListener(this); 54 layout.addView(edtSend); 55 56 //送信ボタンの生成 57 btnSend = new Button(this) ; 58 btnSend.setText("送信"); 59 btnSend.setOnClickListener(this); 60 layout.addView(btnSend); 61 62 //受信ラベルの生成 63 lblReceive = new TextView(this); 64 lblReceive.setText(""); 65 lblReceive.setTextSize(20.0f); 66 lblReceive.setTextColor(Color.BLUE); 67 lblReceive.setLayoutParams(new LinearLayout.LayoutParams(MP,WC)); 68 layout.addView(lblReceive); 69 } 70 //アクティビティ開始時に呼ばれる 71 @Override 72 public void onStart() { 73 super.onStart(); 74 75 //スレッドの生成 76 Thread thread = new Thread(){ 77 public void run() { 78 try { 79 connect(IP, 8081); 80 } catch (Exception e) { 81 } 82 } 83 }; 84 thread.start(); 85 } 86 87 //アクティビティの停止時に呼ばれる 88 @Override 89 public void onStop(){ 90 super.onStop(); 91 disconnect(); 92 } 93 //受信テキストの追加 94 private void addText(final String text) { 95 //ハンドラの生成 96 handler.post(new Runnable(){ 97 public void run() { 98 lblReceive.setText(text+BR+lblReceive.getText()); 99 } 100 }); 101 } 102 103 // 接続 104 private void connect(String ip, int port) { 105 int size ; 106 String str ; 107 byte[] w = new byte[1024] ; 108 try{ 109 //ソケット通信 110 addText("接続中"); 111 socket = new Socket(ip, port) ; 112 in = socket.getInputStream() ; 113 out = socket.getOutputStream(); 114 addText("接続完了"); 115 116 //受信ループ 117 while (socket != null && socket.isConnected()) { 118 //データの受信 119 size = in.read(w); 120 if (size <= 0) continue ; 121 str = new String(w, 0, size, "UTF-8"); 122 123 //ラベルへの文字追加 124 addText("通信失敗しました1"); 125 } 126 } catch (Exception e) { 127 addText("通信失敗しました2"); 128 } 129 } 130 131 //切断 132 private void disconnect() { 133 try { 134 socket.close(); 135 socket = null ; 136 } catch (Exception e) { 137 } 138 } 139 140 //ボタンクリックイベントの処理 141 public void onClick(View v) { 142 //スレッドの生成 143 Thread thread = new Thread(new Runnable() {public void run(){ 144 error = false ; 145 try { 146 //データの送信 147 if (socket != null && socket.isConnected()){ 148 byte[] w = edtSend.getText().toString().getBytes("UTF8"); 149 out.write(w) ; 150 out.flush(); 151 } 152 } catch (Exception e) { 153 error = true ; 154 } 155 //ハンドラの生成 156 handler.post(new Runnable(){ public void run(){ 157 if(!error){ 158 edtSend.setText(""); 159 } else { 160 addText("通信失敗しました3"); 161 } 162 }}); 163 }}); 164 thread.start(); 165 } 166}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

手始めとして、ソケット通信を2台のスマホで行うためには、

この時点ですでに通信初心者の範疇を超えてしまっており、ひとつふたつの回答で伝えられる範囲とは思えないのですが、せめて知らなければならない範囲だけでも書いてみます。

Java

1socket = new Socket(ip, port) ;

Socketというのは、Java(Android)でTCP/IPクライアントソケットを扱うために使用します。
TCPというのはIPプロトコルを使って相手と接続し双方向通信を行うためのプロトコルです。
この時点で???であれば、まぁ自分と相手の二人の電話と思ってもいいです。

さて上記のSocket(ip,port)に戻りますが、これはクライアント側(接続を要求する側)が接続先を指定してsocketを作る、という意味になります。
接続先はIPアドレスとポート番号で指定します。相手の電話番号みたいなものです。
相手先がIPアドレスだけでないのは、同じIPアドレスでもさらに複数接続を行えるようにポート番号も必要とするからです。また、目的によってポート番号を変えている場合もあります。

ブラウザでURLを打ち込むときはたいていサーバ名を書きますが、
https://developer.android.com

このサーバ名(developer.android.com)はDNSでIPアドレスに変換するとして、じゃぁポート番号書かなくていいかというと、実際には暗黙のポート番号(httpsの場合は443)が指定されたことになっています。

試しに
https://developer.android.com:443
としてもちゃんと繋がります。

というわけで、

IPアドレスと、ポート番号は何番を入力すればよいのでしょうか?

に対する回答は、「接続待ちしているサーバ側のIPアドレスとポート番号」となります。
ここでおそらく「サーバ側ってなに?」ってなっているのではないでしょうか。

Socketの説明に戻りますが、SocketはTCP/IPクライアントソケットを扱うために使用します。
つまり、2台のAndroidデバイスでTCP/IP接続による通信を行いたいのであれば、1台はSocketでも良いですが、もう1台はサーバ側ソケットでなければなりません。
サーバ側ソケットは ServerSocket を使用します。
まずサーバ側のデバイスが ServerSocket で待ち状態になって(ポート番号はその時にサーバ側が決めます)、それに対してクライアント側のデバイスがSocketで接続すれば、めでたく通信開始になります。

[1]で行って確認するIPアドレスと、[2]で行うIPアドレスが違うのですが、なぜなのでしょうか?

[1]はデバイス側が知っている自分のIPアドレス、
[2]はインターネット側から見たデバイスのIPアドレスです。
なぜ違うのかというと、ネットワークが違うからです。
そのそもIPアドレスはどうやって決まるかというと、「なんらかの申請を行って取得する」場合と、「自動で決めてもらう」場合とあります。[1]も[2](こっちはおそらくですが)も、自動で決めてもらっています。
誰が決めているかというと、[1]はWi-Fiルータ、[2]は契約したプロバイダです。

ほぼすべてのWi-Fiルータは、Wi-Fi接続したデバイスそれぞれにIPアドレス(これは[1])を与えて、またそれらのデバイスからインターネット側に接続要求があった場合はプロバイダから貰っているIPアドレス(これは[2])に変換した上でネット上のサーバと接続する、という仕組みを持っています。
だから[1]と[2]ではIPアドレスが違いますし、仮にWi-Fiで何台もデバイスを繋げてどのデバイスから[2]を表示しても同じIPアドレスになるはずです。

TCP/IPで接続するためには相手先のIPアドレスとポート番号がわかれば良いのですが、インターネット側からWi-Fiルータの内側にいるデバイスに接続するのは困難である(だってIPアドレスわからないんだもん)ということになります。
さらに言えば、[2]で表示されるIPアドレスも「世界で唯一のIPアドレス(固定IPとか言われます)」でない可能性があります。
そうなるといよいよ「IPアドレスわからない」となってきます。

いきなり外界での接続は諦めるとして、Wi-Fiルータの内側に2台ともある場合、つまり2台とも同じWi-Fiルータに繋がっている場合であればどうでしょうか?
それでも問題はあります。IPアドレスを与えてくれたのはWi-Fiルータですが、接続先デバイスのIPアドレスはどうやって知るのでしょう?
2台の設定アプリを両方とも目視で確認する、ということでなければ、どうにかして接続先デバイスのIPアドレスを自分で特定しなければなりません。
この処理を「探索」とか「発見」とか呼びますが、「探索」させるための手がかりをお互いに発信(「俺はここにいるよー」、って感じ)して、それをお互いに探索して、見つかったらその相手に接続します。

「俺はここにいるよー」ってのは接続前に行うことですから、接続が前提であるTCPでは無理です。IPを使った通信には、接続しないで通信できるUDPという別のプロトコルがあります。UDPを使い、さらに相手を特定せずスピーカーのように
「俺はここにいるよー」と声を張り上げる仕組みが必要です。

一気に説明しましたが、1万分の1でも伝わったでしょうか?

実のところ2台のデバイスで通信を行いたい場合でも、直接接続するのではなく、別にサーバを用意してサーバを介して通信するのが遥かに簡単ですし、よほどの理由がなければまずそれを薦めます。

投稿2018/10/16 05:58

daisuke7

総合スコア1563

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

H30_inenaga

2018/10/16 10:51 編集

丁寧な回答をありがとうございます。 長文のため、細かに分けてご質問させていただきます。 1.まず、回答からイメージしたことは、 指導者(クライアント)Socket⇔受講者(サーバ)ServerSocket で、相互にやり取りをする、です。 2台のスマホを、それぞれスマホA、スマホBとすると、 スマホAには、質問に掲載したソースコードがコンパイルされたアプリが搭載されているとして、 スマホBには、ServerSocketというプログラムをコンパイルしたアプリを登載しなければならないのでしょうか?
H30_inenaga

2018/10/16 10:51

2.つまり、サーバなしでは、プライベートIPアドレスでも、グローバルIPアドレスでも難しいということでしょうか?
daisuke7

2018/10/16 10:55

1.アプリ自体は共用でも良いですが、つながっている瞬間はどちらかがServerSocket、もう片方はSocketになりますね。アプリを別に出来るならとてもシンプルになって色んな問題が消えます。 2.両方プライベートアドレス、かつサーバとクライアントのアプリが完全に分かれているならそんなに難しくありません。
H30_inenaga

2018/10/16 10:57

3. >TCP/IPで接続するためには相手先のIPアドレスとポート番号がわかれば良いのですが、インターネット側からWi-Fiルータの内側にいるデバイスに接続するのは困難である(だってIPアドレスわからないんだもん)ということになります。 さらに言えば、[2]で表示されるIPアドレスも「世界で唯一のIPアドレス(固定IPとか言われます)」でない可能性があります。 そうなるといよいよ「IPアドレスわからない」となってきます。 いきなり外界での接続は諦めるとして、Wi-Fiルータの内側に2台ともある場合、つまり2台とも同じWi-Fiルータに繋がっている場合であればどうでしょうか? それでも問題はあります。IPアドレスを与えてくれたのはWi-Fiルータですが、接続先デバイスのIPアドレスはどうやって知るのでしょう? 2台の設定アプリを両方とも目視で確認する、ということでなければ、どうにかして接続先デバイスのIPアドレスを自分で特定しなければなりません。 この処理を「探索」とか「発見」とか呼びますが、「探索」させるための手がかりをお互いに発信(「俺はここにいるよー」、って感じ)して、それをお互いに探索して、見つかったらその相手に接続します。 ↑これは、携帯回線網でソケット通信を行うことは、難しいということでしょうか? そうでしたら、携帯回線網で2台のスマホを接続するのにおあつらえ向きな通信方法があるのでしょうか? (HTTP通信?ソケット通信でポート80番でカプセル化?etc...)
daisuke7

2018/10/16 11:11

3.難しいのは「接続先のIPアドレスをどうやって特定するか?」です。 HTTPで繋げるとしても結局はその問題になります。 別にサーバを用意するのは難しいのでしょうか?
H30_inenaga

2018/10/16 11:14

度々、質問で申し訳ないです。初心者の範疇を超えるというのは、誠ですね...汗 1.えっと、アプリ自体は共用でも良いということは、スマホA,Bどちらにも質問に掲載したソースコードをコンパイルしたアプリが入っていれば良いという意味で間違いないでしょうか? >アプリを別にしたら この方法、もしくはソースコード?URL?をご存知でしたら教えてください! 2. 両方プライベートIPアドレス、というのは質問に掲載した[1]のやり方で確認するIPアドレスのことですよね? サーバとクライアントをはっきり分けるとは、1.でお答えくださったアプリを別にする、という方法でしょうか? 色々、勉強不足で申し訳ないです。よろしくお願いします。
H30_inenaga

2018/10/16 11:17

3.サーバを別に用意する、ことは基本的に大丈夫なのですが、それだと距離的に制限があるのかな、と思いまして(Wifiルータの距離など?)、携帯回線(サーバなし?)でしたら距離関係なく接続できそうなイメージがあったからお聞きしました。
daisuke7

2018/10/16 11:20

>1.えっと、アプリ自体は共用でも良いということは、 いや、Socketを使ってクライアント側として動くか、ServerSocketで待ち受けてサーバとして動くか、その二つの機能はまったく別物ですので、別のアプリにしてもいいし、同じアプリに二つの機能を組み込んで切り替えられるようにしても良い、という意味です。 >>アプリを別にしたら >この方法、もしくはソースコード?URL?をご存知でしたら教えてください! いやそれはほんとに別アプリとして作るだけのことです。 > 2. 両方プライベートIPアドレス、というのは質問に掲載した[1]のやり方で確認するIPアドレス そうですね。 > 3.サーバを別に用意する、ことは基本的に大丈夫なのですが、それだと距離的に制限があるのかな、 ここでいうサーバというのは、インターネット上のサーバ、たとえば http://xxxxx で繋がるサーバのことです。インターネット上のサーバですから距離は関係ありませんし、Wi-Fiだろうが4G回線だろうが関係ありません。2台のデバイスがどちらもそのサーバに接続して、間接的に通信することになります。
H30_inenaga

2018/10/16 12:14

>いや、Socketを使ってクライアント側として動くか、ServerSocketで待ち受けてサーバとして動くか 質問に掲載したソースコードは、どちらの役目として動いても良いようにプログラムしていることになりますか?(ソースコードは本を参考にしています。) それならば、スマホA,B両方ともこのソースコードをコンパイルしたアプリが必要ですか? >ここでいうサーバというのは、インターネット上のサーバ、たとえば 承知しました。
H30_inenaga

2018/10/16 12:15

文章だけでは、伝わりにくいので、後程、自分がつまづいている部分の画像を アップします。よろしくお願いします。
daisuke7

2018/10/16 12:16

質問にあるコードはSocketしか使っていないですよね? ServerSocketは使っていません。つまりクライアント側としてしか使えないコードになっています。
H30_inenaga

2018/10/20 04:09

質問、大丈夫でしょうか? 画像の件は、後回しにさせていただいて、 ソケット通信をするときに80番のポート番号、これはブラウザ閲覧の用途によく使われるそうですが、ソケット通信では使えるのでしょうか? また、8081番に見せかけるようなカプセル化は可能でしょうか?
daisuke7

2018/10/20 07:14

なぜソケット通信にこだわるのか分かりませんが、どうしてもソケットでやりたいのでしたらまずTCP/IPについて一通り学ぶべきです。 80番はhttpで暗黙的に使われるポート番号です。こういったポート番号は well knownポート番号と呼ばれます。
H30_inenaga

2018/10/24 06:46

承知しました。また質問を載せますのでそちらも確認いただけると幸いです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問