web-dev-qa-db-ja.com

Androidでソケット接続を作成する方法は?

ソケット接続を作成する必要があるアプリケーションがあります。私の要件は、ソケット接続が確立されたら、個人的に閉じるまで生き続ける必要があるということです。そして、3分ごとにデータパケットを相手に送信する必要があります。誰でも私にこれを行うのに役立つコードサンプルを提供できますか?

39
Nilanchal

AndroidはJavaと同じです: http://www.Oracle.com/technetwork/Java/socket-140484.html

知っておくべきこと:

  1. 電話がスリープ状態になると、アプリは実行されなくなるため、ソケットは最終的にタイムアウトします。ウェイクロックでこれを防ぐことができます。これはデバイスのバッテリーをものすごく消費します-私はそのアプリを使用しないことを知っています。
  2. アプリがアクティブでない場合でも、これを継続的に行う場合は、サービスを使用する必要があります。
  3. アクティビティとサービスは、特にアクティブでないアプリの一部である場合は、OSによっていつでも強制終了できます。

コードのスケジュールされた実行が必要な場合は、AlarmManagerをご覧ください。

ユーザーがアプリを使用しなくなった場合(アプリが非アクティブ)でも、コードを実行してデータを受信する必要がありますか?

53
Peter Knego

ここでは、この投稿で、デバイス間または同じモバイルの2つのアプリケーション間でソケットを確立するための詳細なコードを見つけます。

以下のコードをテストするには、2つのアプリケーションを作成する必要があります。

両方のアプリケーションのマニフェストファイルで、以下の権限を追加します

<uses-permission Android:name="Android.permission.INTERNET" />

最初のアプリコード:クライアントソケット

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <TableRow
        Android:id="@+id/tr_send_message"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:gravity="center"
        Android:layout_alignParentLeft="true"
        Android:layout_alignParentStart="true"
        Android:layout_alignParentTop="true"
        Android:layout_marginTop="11dp">

        <EditText
            Android:id="@+id/edt_send_message"
            Android:layout_width="0dp"
            Android:layout_height="wrap_content"
            Android:layout_weight="1"
            Android:layout_marginRight="10dp"
            Android:layout_marginLeft="10dp"
            Android:hint="Enter message"
            Android:inputType="text" />

        <Button
            Android:id="@+id/btn_send"
            Android:layout_width="wrap_content"
            Android:layout_height="wrap_content"
            Android:layout_marginRight="10dp"
            Android:text="Send" />
    </TableRow>

    <ScrollView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_alignParentLeft="true"
        Android:layout_alignParentStart="true"
        Android:layout_below="@+id/tr_send_message"
        Android:layout_marginTop="25dp"
        Android:id="@+id/scrollView2">

        <TextView
            Android:id="@+id/tv_reply_from_server"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:orientation="vertical" />
    </ScrollView>
</RelativeLayout>

MainActivity.Java

import Android.os.Bundle;
import Android.os.Handler;
import Android.support.v7.app.AppCompatActivity;
import Android.view.View;
import Android.widget.Button;
import Android.widget.EditText;
import Android.widget.TextView;

import Java.io.BufferedReader;
import Java.io.IOException;
import Java.io.InputStreamReader;
import Java.io.OutputStream;
import Java.io.PrintWriter;
import Java.net.Socket;

/**
 * Created by Girish Bhalerao on 5/4/2017.
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private TextView mTextViewReplyFromServer;
    private EditText mEditTextSendMessage;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Button buttonSend = (Button) findViewById(R.id.btn_send);

        mEditTextSendMessage = (EditText) findViewById(R.id.edt_send_message);
        mTextViewReplyFromServer = (TextView) findViewById(R.id.tv_reply_from_server);

        buttonSend.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {

            case R.id.btn_send:
                sendMessage(mEditTextSendMessage.getText().toString());
                break;
        }
    }

    private void sendMessage(final String msg) {

        final Handler handler = new Handler();
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {

                try {
                    //Replace below IP with the IP of that device in which server socket open.
                    //If you change port then change the port number in the server side code also.
                    Socket s = new Socket("xxx.xxx.xxx.xxx", 9002);

                    OutputStream out = s.getOutputStream();

                    PrintWriter output = new PrintWriter(out);

                    output.println(msg);
                    output.flush();
                    BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
                    final String st = input.readLine();

                    handler.post(new Runnable() {
                        @Override
                        public void run() {

                            String s = mTextViewReplyFromServer.getText().toString();
                            if (st.trim().length() != 0)
                                mTextViewReplyFromServer.setText(s + "\nFrom Server : " + st);
                        }
                    });

                    output.close();
                    out.close();
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });

        thread.start();
    }
}

2番目のアプリコード-サーバーソケット

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <Button
        Android:id="@+id/btn_stop_receiving"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="STOP Receiving data"
        Android:layout_alignParentTop="true"
        Android:enabled="false"
        Android:layout_centerHorizontal="true"
        Android:layout_marginTop="89dp" />

    <ScrollView
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:layout_below="@+id/btn_stop_receiving"
        Android:layout_marginTop="35dp"
        Android:layout_alignParentLeft="true"
        Android:layout_alignParentStart="true">

        <TextView
            Android:id="@+id/tv_data_from_client"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content"
            Android:orientation="vertical" />
    </ScrollView>

    <Button
        Android:id="@+id/btn_start_receiving"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:text="START Receiving data"
        Android:layout_alignParentTop="true"
        Android:layout_centerHorizontal="true"
        Android:layout_marginTop="14dp" />
</RelativeLayout>

MainActivity.Java

import Android.os.Bundle;
import Android.os.Handler;
import Android.support.v7.app.AppCompatActivity;
import Android.view.View;
import Android.widget.Button;
import Android.widget.TextView;

import Java.io.BufferedReader;
import Java.io.IOException;
import Java.io.InputStreamReader;
import Java.io.PrintWriter;
import Java.net.ServerSocket;
import Java.net.Socket;

/**
 * Created by Girish Bhalerao on 5/4/2017.
 */
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    final Handler handler = new Handler();

    private Button buttonStartReceiving;
    private Button buttonStopReceiving;
    private TextView textViewDataFromClient;
    private boolean end = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        buttonStartReceiving = (Button) findViewById(R.id.btn_start_receiving);
        buttonStopReceiving = (Button) findViewById(R.id.btn_stop_receiving);
        textViewDataFromClient = (TextView) findViewById(R.id.tv_data_from_client);

        buttonStartReceiving.setOnClickListener(this);
        buttonStopReceiving.setOnClickListener(this);

    }

    private void startServerSocket() {

        Thread thread = new Thread(new Runnable() {

            private String stringData = null;

            @Override
            public void run() {

                try {

                    ServerSocket ss = new ServerSocket(9002);

                    while (!end) {
                        //Server is waiting for client here, if needed
                        Socket s = ss.accept();
                        BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
                        PrintWriter output = new PrintWriter(s.getOutputStream());

                        stringData = input.readLine();
                        output.println("FROM SERVER - " + stringData.toUpperCase());
                        output.flush();

                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        updateUI(stringData);
                        if (stringData.equalsIgnoreCase("STOP")) {
                            end = true;
                            output.close();
                            s.close();
                            break;
                        }

                        output.close();
                        s.close();
                    }
                    ss.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        });
        thread.start();
    }

    private void updateUI(final String stringData) {

        handler.post(new Runnable() {
            @Override
            public void run() {

                String s = textViewDataFromClient.getText().toString();
                if (stringData.trim().length() != 0)
                    textViewDataFromClient.setText(s + "\n" + "From Client : " + stringData);
            }
        });
    }

    @Override
    public void onClick(View v) {

        switch (v.getId()) {
            case R.id.btn_start_receiving:

                startServerSocket();
                buttonStartReceiving.setEnabled(false);
                buttonStopReceiving.setEnabled(true);
                break;

            case R.id.btn_stop_receiving:

                //stopping server socket logic you can add yourself
                buttonStartReceiving.setEnabled(true);
                buttonStopReceiving.setEnabled(false);
                break;
        }
    }
}
15
Girish Bhalerao

簡単なソケットサーバーアプリの例

https://stackoverflow.com/a/35971718/895245 にクライアントの例を既に投稿しているので、ここにサーバーの例を示します。

このサンプルアプリは、入力のROT-1暗号を返すサーバーを実行します。

次に、Exitボタンといくつかのスリープ遅延を追加する必要がありますが、これで開始できます。

それで遊ぶには:

Androidソケットは、いくつかの許可の問題に対処する必要があることを除いて、Javaのソケットと同じです。

src/com/cirosantilli/Android_cheat/socket/Main.Java

package com.cirosantilli.Android_cheat.socket;

import Android.app.Activity;
import Android.app.IntentService;
import Android.content.Intent;
import Android.os.Bundle;
import Android.util.Log;

import Java.io.BufferedReader;
import Java.io.IOException;
import Java.io.InputStreamReader;
import Java.io.PrintStream;
import Java.net.ServerSocket;
import Java.net.Socket;

public class Main extends Activity {
    static final String TAG = "AndroidCheatSocket";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d(Main.TAG, "onCreate");
        Main.this.startService(new Intent(Main.this, MyService.class));
    }

    public static class MyService extends IntentService {
        public MyService() {
            super("MyService");
        }
        @Override
        protected void onHandleIntent(Intent intent) {
            Log.d(Main.TAG, "onHandleIntent");
            final int port = 12345;
            ServerSocket listener = null;
            try {
                listener = new ServerSocket(port);
                Log.d(Main.TAG, String.format("listening on port = %d", port));
                while (true) {
                    Log.d(Main.TAG, "waiting for client");
                    Socket socket = listener.accept();
                    Log.d(Main.TAG, String.format("client connected from: %s", socket.getRemoteSocketAddress().toString()));
                    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    PrintStream out = new PrintStream(socket.getOutputStream());
                    for (String inputLine; (inputLine = in.readLine()) != null;) {
                        Log.d(Main.TAG, "received");
                        Log.d(Main.TAG, inputLine);
                        StringBuilder outputStringBuilder = new StringBuilder("");
                        char inputLineChars[] = inputLine.toCharArray();
                        for (char c : inputLineChars)
                            outputStringBuilder.append(Character.toChars(c + 1));
                        out.println(outputStringBuilder);
                    }
                }
            } catch(IOException e) {
                Log.d(Main.TAG, e.toString());
            }
        }
    }
}

Serviceまたは他のバックグラウンドメソッドなどが必要です。 Android.os.NetworkOnMainThreadExceptionの修正方法

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:Android="http://schemas.Android.com/apk/res/Android"
      package="com.cirosantilli.Android_cheat.socket"
      Android:versionCode="1"
      Android:versionName="1.0">
    <uses-sdk Android:minSdkVersion="22" />
    <uses-permission Android:name="Android.permission.INTERNET" />
    <application Android:label="AndroidCheatsocket">
        <activity Android:name="Main">
            <intent-filter>
                <action Android:name="Android.intent.action.MAIN" />
                <category Android:name="Android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service Android:name=".Main$MyService" />
    </application>
</manifest>

追加する必要があります:<uses-permission Android:name="Android.permission.INTERNET" />またはその他: JavaソケットIOException-許可が拒否されました

GitHubでbuild.xmlhttps://github.com/cirosantilli/Android-cheat/tree/92de020d0b708549a444ebd9f881de7b240b3fbc/socket