투케이2K

159. (TWOK/UTIL) [Android/Java] C_Bluetooth_Spp_Server_Module : 블루투스 SPP 통신 서버 모듈 클래스 본문

투케이2K 유틸파일

159. (TWOK/UTIL) [Android/Java] C_Bluetooth_Spp_Server_Module : 블루투스 SPP 통신 서버 모듈 클래스

투케이2K 2025. 2. 23. 12:57

[설 명]

프로그램 : Android / Java

설 명 : C_Bluetooth_Spp_Server_Module : 블루투스 SPP 통신 서버 모듈 클래스

 

[소스 코드]

package com.example.javaproject.C_Module;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;

import androidx.core.app.ActivityCompat;

import com.example.javaproject.C_Util;
import com.example.javaproject.S_FinalData;
import com.example.javaproject.S_Log;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.UUID;

public class C_Bluetooth_Spp_Server_Module {


    /**
     * // --------------------------------------------------------------------------------------
     * TODO [클래스 설명]
     * // --------------------------------------------------------------------------------------
     * 1. [설명] : 블루투스 SPP 통신 사용 모듈
     * // --------------------------------------------------------------------------------------
     * 2. 필요 퍼미션 : 필요 퍼미션 권한 : 위치 및 GPS 권한 , 블루투스 권한 - SCAN , ADVERTISE , CONNECT
     *
     * // TODO [공통]
     * <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
     * <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
     *
     * <uses-permission android:name="android.permission.BLUETOOTH"/>
     * <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
     * <uses-feature android:name="android.hardware.bluetooth_le" />
     *
     * // TODO [안드로이드 12 이상 : S 버전]
     * <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
     * <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE"/>
     * <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
     * // --------------------------------------------------------------------------------------
     * */





    /**
     * // --------------------------------------------------------------------------------------
     * TODO [빠른 로직 찾기 : 주석 로직 찾기]
     * // --------------------------------------------------------------------------------------
     *
     * // --------------------------------------------------------------------------------------
     *
     * // --------------------------------------------------------------------------------------
     *
     * // --------------------------------------------------------------------------------------
     *
     * // --------------------------------------------------------------------------------------
     *
     * // --------------------------------------------------------------------------------------
     */





    // ------------------------------------------------------------------------------------------
    // TODO [사용 방법]
    // ------------------------------------------------------------------------------------------
    /*
    try {

        new Thread(){
				@Override
				public void run(){
					try {

                        // --------------------------------------
                        // TODO [1]. [서버 모듈 클래스 인스턴스 초기화]
                        // --------------------------------------
                        C_Bluetooth_Spp_Server_Module c_socket_server_module = C_Bluetooth_Spp_Server_Module.getInstance();
                        c_socket_server_module.setContext(A_Intro.this);


                        // --------------------------------------
                        // TODO [2]. [서버 활성 수행]
                        // --------------------------------------
                        if(c_socket_server_module.openServer() == true) { // TODO [소켓 서버 열기 성공 상태 확인]

                        }
                        else {
                            S_Log._E_("C_Bluetooth_Spp_Server_Module :: openServer :: 서버 활성 실패", null);
                        }

					}
					catch (Exception e) {
						e.printStackTrace();
					}
				}
			}.start();

    }
    catch (Exception e) {
        e.printStackTrace();
    }
     */
    // ------------------------------------------------------------------------------------------






    // ------------------------------------------------------------------------------------------
    // TODO [전역 변수 선언]
    // ------------------------------------------------------------------------------------------
    private String ACTIVITY_NAME = "C_Bluetooth_Spp_Server_Module";

    private Context mMainCtx; // [컨텍스트]

    private static final UUID UUID_ARRAY[] = {
            UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"), // TODO [Client : SmartPhone / Server : SmartPhone]
            UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") // TODO [Client : SmartPhone / Server : Device]
    };

    private BluetoothAdapter bluetoothAdapter; // [블루투스 어댑터]

    BluetoothServerSocket mServer = null; // [서버 소켓]
    BluetoothSocket mSocket = null; // [클라이언트 소켓]
    Thread mThread = null; // [서버 스레드]

    private InputStream inputStream; // [메시지 수신 스트림]
    private OutputStream outputStream; // [메시지 송신 스트림]





    // ------------------------------------------------------------------------------------------
    // TODO [콘텍스트 지정]
    // ------------------------------------------------------------------------------------------
    public void setContext(Context ctx) {
        mMainCtx = ctx;
    }





    // ------------------------------------------------------------------------------------------
    // TODO [인스턴스 생성]
    // ------------------------------------------------------------------------------------------
    public static C_Bluetooth_Spp_Server_Module getInstance() {
        return C_Bluetooth_Spp_Server_Module.LazyHolder.INSTANCE;
    }

    private static class LazyHolder {
        private static final C_Bluetooth_Spp_Server_Module INSTANCE = new C_Bluetooth_Spp_Server_Module();
    }





    // ------------------------------------------------------------------------------------------
    // TODO [블루투스 소켓 서버 활성 수행]
    // ------------------------------------------------------------------------------------------
    public synchronized boolean openServer() {

        // [변수 선언]
        final boolean[] isConnection = {false};
        String M_LOG = "";

        // [로직 처리 수행]
        try {

            if (mMainCtx != null) {

                // [블루투스 지원 가능 기기 및 활성 상태 확인]
                bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
                if (bluetoothAdapter == null) {
                    M_LOG = "[Error] :: 블루투스 기능 지원 여부 확인 필요 (Bluetooth is not supported on this device)";
                } else {

                    if (bluetoothAdapter.isEnabled() == false) {
                        M_LOG = "[Error] :: 블루투스 기능 활성 상태 확인 필요 (Bluetooth isEnabled False)";
                    } else {

                        // [기능 사용에 필요한 권한 부여 상태 확인]
                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // TODO [안드로이드 12 이상]

                            if (ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
                                    || ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED

                                    || ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED
                                    || ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED
                                    || ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.BLUETOOTH_ADVERTISE) != PackageManager.PERMISSION_GRANTED) {

                                M_LOG = "[Error] :: 안드로이드 12 이상 - 블루투스 기능 사용 퍼미션 권한 확인 필요 (Permission Not Granted)";
                            }
                        } else { // TODO [안드로이드 12 미만]
                            if (ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
                                    || ActivityCompat.checkSelfPermission(mMainCtx, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {

                                M_LOG = "[Error] :: 안드로이드 12 미만 - 블루투스 기능 사용 퍼미션 권한 확인 필요 (Permission Not Granted)";
                            }
                        }


                        // TODO [에러 발생한 적이 없는 경우 : 상위에서 방어 로직 통과한 경우]
                        if (C_Util.stringNotNull(M_LOG) == false) {

                            if (this.mServer != null) { // TODO [소켓이 널이 아닌 경우]
                                M_LOG = "[Error] :: 블루투스 서버 소켓 이미 활성 된 상태 (Server Socket Not Null)";
                            } else { // TODO [소켓이 널인 경우]

                                // TODO [서버 소켓 생성]
                                mServer = bluetoothAdapter.listenUsingRfcommWithServiceRecord(ACTIVITY_NAME, UUID_ARRAY[0]);

                                M_LOG = "[Success] :: Bluetooth Socket Server Open (" + String.valueOf(bluetoothAdapter.getName()) + ")";


                                // TODO [리턴 변수 삽입]
                                isConnection[0] = true;


                                // TODO [실시간 클라이언트 메시지 수신 확인] : 1회 연결 후 클라이언트 접속 해제시 break 탈출
                                mThread = new Thread(new Runnable() {
                                    @Override
                                    public void run() {
                                        try {

                                            // ------------------------------------------------

                                            // TODO [클라이언트 소켓 접속 허용 설정]
                                            mSocket = mServer.accept();

                                            // ------------------------------------------------

                                            // TODO [스트림 초기화]
                                            inputStream = mSocket.getInputStream();
                                            outputStream = mSocket.getOutputStream();

                                            // ------------------------------------------------

                                            // TODO [while 메시지 수신 상태 확인]
                                            byte[] buffer = new byte[1024];
                                            int bytes;

                                            while (true) {

                                                try {
                                                    // TODO [클라이언트로부터 데이터 수신]
                                                    bytes = inputStream.read(buffer);
                                                    String receivedData = new String(buffer, 0, bytes);

                                                    String client = "Client Mac :: " + String.valueOf(mSocket.getRemoteDevice().getAddress());

                                                    // [로그 출력]
                                                    S_Log._W_("[클라이언트 >> 서버] :: 전달 받은 메시지 확인", new String[]{
                                                            "Client Info :: " + String.valueOf(client),
                                                            "Client Message :: " + String.valueOf(receivedData)
                                                    });


                                                    // TODO [클라이언트로 메시지 전송 수행]
                                                    if (outputStream != null) {
                                                        try {
                                                            outputStream.write(receivedData.getBytes());

                                                            S_Log._W_("[서버 >> 클라이언트] :: 전송 메시지 확인", new String[]{
                                                                    "Client Info :: " + String.valueOf(client),
                                                                    "Send Message :: " + String.valueOf(receivedData)
                                                            });

                                                        } catch (Exception e) {
                                                            e.printStackTrace();
                                                        }
                                                    } else {
                                                        S_Log._E_(ACTIVITY_NAME + " :: openServer :: Server To Client Message Send Fail :: outputStream is null", null);
                                                    }

                                                }
                                                catch (Exception ey){
                                                    ey.printStackTrace();
                                                    S_Log._E_(ACTIVITY_NAME + " :: openServer :: Server While Break", null);
                                                    break; // TODO [루프 탈출]
                                                }

                                            } // TODO [End While]

                                            // ------------------------------------------------

                                        } catch (Exception e) {
                                            S_Log._printStackTrace_(null, S_FinalData.LOG_BUG_STATE, null, e);

                                            // [Exception 발생 시 소켓 연결 종료]
                                            closeSocket();
                                        }
                                    }
                                });
                                mThread.start(); // [스레드 수행]

                            }

                        }

                    }
                }

            }
            else {
                M_LOG = "[Error] :: mMainCtx Is Null";
            }

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

            // [로그 삽입]
            M_LOG = "[Exception] :: " + String.valueOf(e.getMessage());

            // [Exception 발생 시 소켓 연결 종료]
            closeSocket();

        }

        S_Log._W_(ACTIVITY_NAME + " :: openServer :: 블루투스 서버 소켓 활성 수행", new String[]{
                "M_LOG :: " + M_LOG,
                "RETURN :: " + isConnection[0]
        });

        // [리턴 반환 수행]
        return isConnection[0];

    }





    // ------------------------------------------------------------------------------------------
    // TODO [서버 소켓 연결 종료]
    // ------------------------------------------------------------------------------------------
    public synchronized void closeSocket() {

        // [변수 선언]
        String M_LOG = "";

        // [로직 처리 수행]
        try {

            // [서버 소켓 닫기]
            if (mServer != null){
                mServer.close();
                mServer = null;
            }

            // [클라이언트 소켓 닫기]
            if(this.mSocket != null) {
                mSocket.close();
                mSocket = null;
            }

            // [스트림 초기화]
            if (inputStream != null){
                inputStream.close();
                inputStream = null;
            }
            if (outputStream != null){
                outputStream.close();
                outputStream = null;
            }

            // [스레드 닫기]
            if (mThread != null){
                mThread.interrupt();
            }

            M_LOG = "[Success] :: bluetoothServerSocket Closed";
        }
        catch (Exception e) {
            S_Log._printStackTrace_(null, S_FinalData.LOG_BUG_STATE, null, e);

            M_LOG = "[Exception] :: " + String.valueOf(e.getMessage());
        }

        S_Log._E_(ACTIVITY_NAME + " :: closeSocket :: 블루투스 서버 소켓 연결 종료 수행", new String[]{ "M_LOG :: " + String.valueOf(M_LOG) });

    }



} // TODO [클래스 종료]
 
반응형
Comments