ツナドーナツ・技術メモ帳

色々なものを作る過程で分からなかったことなどを書いていきます

Androidでソケット通信 Java(Android)からC++へ

Android端末でソケット通信ができるようになったのでメモ

Androidでソケット通信を行う際は、AndroidManifest.xmlパーミッションを通す必要があります。
packageとapplicationの間に
<uses-permission android:name="android.permission.INTERNET" />
を追記すればOKです。

あと、通信などの重たい処理をする際はUIスレッドとは別のスレッドで処理を行わなければなりません。AsyncTaskで非同期処理させないと止められてしまうので注意です。

Android側のソースコード(MainActivity.java)

package .....

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

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

        Button sendImageButton = findViewById(R.id.sendImageButton);
        sendImageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                byte src_img[] = {10, 20, 30};
                SocketThread sockTask = new SocketThread(src_img);

                sockTask.execute();
            }
        });
    }
}

Android側のソースコード(SocketThread.java)

package ......

import android.os.AsyncTask;

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;

public class SocketThread extends AsyncTask<Integer, Integer, Integer> {
    byte src_img[];

    SocketThread(byte src_img[]){
        this.src_img = new byte[src_img.length];
        this.src_img = src_img;
    }

    @Override
    protected Integer doInBackground(Integer... src_img){
        String server = "";//自分の環境のアドレス
        int port = 12345;

        try{
             //ソケット通信
            Socket sock = new Socket(server, port);

            OutputStream os = sock.getOutputStream();
            DataOutputStream dos = new DataOutputStream(os);
            
            //送信部分
            //送信するデータがbyte型なのでwrite一回でも送信できます
            for(int i = 0; i < this.src_img.length; i++) {
                System.out.println(i + "回目  " + this.src_img[i]);
                dos.write(this.src_img[i]);
                dos.flush();
            }

            dos.close();
            sock.close();

        }catch(Exception e){
            e.printStackTrace();
        }
        return 0;
    }
}


ジェネリクス(<Integer, Integer, Integer>のこと)は配列を扱えないらしく、execute(10, 20, 30);という風にいれないといけないらしいです。
なので、インスタンス生成する際にSocketThreadのsrc_imgに値を代入しておくことにしました。画像データの時もこれでいけると思います。


サーバ側のソースコード(SocketThread.cpp)

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>

void print_Array(unsigned char buf[]){
        printf("受信内容 : ");
        for(int i = 0; i < sizeof(buf); i++){
                printf("%d, ", buf[i]);
        }
        printf("\n\n");
}

int main(){
        int sock0;
        int sock;
        struct sockaddr_in addr;
        struct sockaddr_in client;
        socklen_t len;

        sock0 = socket(AF_INET, SOCK_STREAM, 0);

        addr.sin_family = AF_INET;
        addr.sin_port = htons(12345);
        addr.sin_addr.s_addr = INADDR_ANY;

        bind(sock0, (struct sockaddr *)&addr, sizeof(addr));

        listen(sock0, 5);

        len = sizeof(client);
        sock = accept(sock0, (struct sockaddr *)&client, &len);

        unsigned char src_img[24];

        sleep(1);
        int result = recv(sock, &src_img, sizeof(src_img), 0);

        if(result != -1){
                printf("正常に受信できました。\n");
                printf("受信したバイト数 = %d\n", result);
                print_Array(src_img);
        }else{
                printf("受信できませんでした。\n");
                printf("受信した文字数 = %d\n", result);
                print_Array(src_img);
        }

        close(sock0);
        close(sock);

        return 0;
}

C++のほうはいたって普通のもので大丈夫です。