Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Archives
Today
Total
관리 메뉴

쨍쨍

#4. AI Smart Home_SocketActivity 본문

프로그래밍 코드/Android Studio

#4. AI Smart Home_SocketActivity

이선선 2024. 12. 17. 19:04

[ SocketActivity 의 기능 ]

 

 

  SocketActivity 클래스는 스마트홈 시스템에서 서버와의 소켓 연결을 관리하는 역할을 담당합니다. 이 클래스는 서버와의 데이터 전송 및 수신, 로그인 및 회원가입 처리, 센서 데이터 요청 및 처리 등을 수행합니다.

  모든 클래스에서 직접 소켓 연결을 처리할 수도 있지만, SocketActivity 클래스를 통해 중앙 집중식으로 소켓 통신을 관리함으로써 서버와의 연결이 끊어지지 않도록 안정적으로 유지할 수 있습니다. 연결이 끊어지더라도, 자동 재연결을 시도하여 시스템의 안정성을 높입니다. 또한 스마트홈 시스템 특성상 서버와의 지속적인 실시간 데이터 수신이 중요하므로, SocketActivity 클래스는 핵심 통신 기능을 담당하며, 안정적인 운영을 돕습니다.

 

 

[ SocketActivity.java ]

 

 

import android.util.Log;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.io.IOException;

public class SocketActivity {

    private static final String TAG = "SocketActivity";
    private static final String SERVER_IP = "ip 주소";
    
    private static final int SERVER_PORT = 12345;

    private static SocketActivity instance;
    private Socket socket;
    private PrintWriter writer;
    private BufferedReader reader;
    private OnDataReceivedListener dataListener;
    private boolean isConnecting = false;
    private boolean isLoginInProgress = false; // 로그인 진행 상태 플래그
    private boolean isConnected = false; // 재연결을 위한 상태 플래그

    private SocketActivity() { }

    public static synchronized SocketActivity getInstance() {
        if (instance == null) {
            instance = new SocketActivity();
        }
        return instance;
    }

    public void setDataListener(OnDataReceivedListener listener) {
        this.dataListener = listener; // 전달받은 리스너를 설정
    }

    public void connectToServer(OnDataReceivedListener listener) {

        if (isConnecting) return;

        isConnecting = true;
        dataListener = listener;

        new Thread(() -> {
            try {
                socket = new Socket(SERVER_IP, SERVER_PORT);
                socket.setSoTimeout(60000); // 타임아웃을 60초로 설정
                writer = new PrintWriter(socket.getOutputStream(), true);
                reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));
                Log.d(TAG, "Connected to server");
//'']
                isConnected = true;

                requestDataFromServer();
                receiveDataFromServer(); // 데이터 수신을 한 번만 호출
                sendRequestSensorData();
                RequestTipData();

            } catch (IOException e) {
                Log.e(TAG, "Failed to connect to server: " + e.getMessage());
                if (dataListener != null) {
                    dataListener.onDataReceived("Connection failed");
                }
            } finally {
                isConnecting = false;
            }
        }).start();
    }

    public void sendData(String data) {
        if (isSocketConnected()) {
            new Thread(() -> {
                writer.println(data);
                writer.flush();
                Log.d(TAG, "Data sent to server: " + data);
            }).start();
        } else {
            Log.e(TAG, "Socket is not connected. Cannot send data.");
        }
    }

    boolean isSocketConnected() {
        return socket != null && socket.isConnected() && !socket.isClosed();
    }


    // 회원가입 데이터
    public void sendSignupData(String username, String name, String phone, String password) {
        if (isSocketConnected()) {
            new Thread(() -> {
                String message = "REGISTER," + username + "," + name + "," + phone + "," + password;
                writer.println(message);
                writer.flush();
                Log.d(TAG, "회원가입 :Sent signup data to server: " + message);
            }).start();
        } else {
            Log.e(TAG, "Socket is not connected. Cannot send signup data.");
        }
    }

    // 로그인 데이터
    public void sendLoginData(String username, String password) {
        if (isLoginInProgress) {
            Log.d(TAG, "Login request is already in progress.");
            return; // 중복 요청 방지
        }

        isLoginInProgress = true; // 로그인 진행 중 상태 설정

        if (isSocketConnected()) {
            new Thread(() -> {
                writer.println("Login_Data");
                writer.flush();
                String message = username + "," + password;
                writer.println(message);
                writer.flush();
                Log.d(TAG, "로그인: Sent login data to server: " + message);
                isLoginInProgress = false; // 요청 완료 후 초기화
            }).start();
        } else {
            Log.e(TAG, "Socket is not connected. Attempting to reconnect and resend login data.");
            connectToServer(data -> {
                sendLoginData(username, password); // 재연결 후 로그인 데이터 전송
                isLoginInProgress = false; // 요청 완료 후 초기화
            });
        }
    }


    // 중복 확인
    public void sendUsernameValidationRequest(String username) {
        if (isSocketConnected()) {
            new Thread(() -> {
                String message = "VALIDATE_USER," + username;
                writer.println(message);
                writer.flush();
                Log.d(TAG, "Sent username validation request to server: " + message);
            }).start();
        } else {
            Log.e(TAG, "Socket is not connected. Cannot send username validation request.");
        }
    }


    // 날씨를 받아오는 코드 (main)
    void requestDataFromServer() {
        if (writer != null) {
            String message = "REQUEST_DATA";
            writer.println(message);
            writer.flush();
            Log.d(TAG, "Sent request to server: " + message);
        } else {
            Log.e(TAG, "Writer is null. Cannot send request.");
        }
    }


    // 날씨 데이터 + 센서 데이터 받아오는 코드 (home)
    void sendRequestSensorData() {
        if (writer != null) {
            String message = "MAIN_DATA";
            writer.println(message);
            writer.flush();
            Log.d(TAG, "Sent request to server: " + message);
        } else {
            Log.e(TAG, "Writer is null. Cannot send request.");
        }
    }

    // GPT Api 받아오는 코드
    void RequestTipData() {
        if (writer != null) {
            String message = "Tip_DATA";
            writer.println(message);
            writer.flush();
            Log.d(TAG, "Sent request to server: " + message);
        } else {
            Log.e(TAG, "Writer is null. Cannot send request.");
        }
    }



    private void receiveDataFromServer() {
        new Thread(() -> {
            try {
                String line;
                while (isSocketConnected() && (line = reader.readLine()) != null) {
                    //line = line.trim().replaceAll("[\\s\\u0000-\\u001F\\u007F]", ""); // 특수 문자 제거
                    line = line.replaceAll("[\\u0000-\\u001F\\u007F]", "");
                    Log.d(TAG, "Processed data received from server: '" + line + "'");

                    // 센서 데이터인지 확인하여 별도 처리
                    if (line.startsWith("SENSOR_DATA")) {
                        String sensorData = line.substring("SENSOR_DATA".length());
                        Log.d(TAG, "Received sensor data: " + sensorData);
                        if (dataListener != null) {
                            dataListener.onDataReceived(sensorData); // 센서 데이터 전달
                            dataListener.onDataReceived(line); // 응답을 클라이언트로 전달
                        }
                    } else {
                        // 그 외 데이터 처리
                        if (dataListener != null) {
                            dataListener.onDataReceived(line);
                        }
                    }
                }
            } catch (SocketTimeoutException e) {
                Log.e(TAG, "Socket read timed out: " + e.getMessage());
                attemptReconnect();
            } catch (IOException e) {
                Log.e(TAG, "Error reading from server: " + e.getMessage());
                disconnect();
            }
        }).start();
    }

    private void attemptReconnect() {
        disconnect();
        try {
            Thread.sleep(5000); // 5초 대기 후 재연결 시도
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        connectToServer(dataListener);
    }

    public void disconnect() {
        try {
            if (writer != null) writer.close();
            if (reader != null) reader.close();
            if (socket != null) socket.close();
            Log.d(TAG, "Disconnected from server");
        } catch (IOException e) {
            Log.e(TAG, "Failed to disconnect: " + e.getMessage());
        } finally {
            isLoginInProgress = false; // 연결이 끊어졌을 때 초기화
            isConnecting = false;
        }
    }

    public interface OnDataReceivedListener {
        void onDataReceived(String data);
    }
}