Notice
Recent Posts
Recent Comments
Link
투케이2K
184. (TWOK/UTIL) [Android/Java] [기능 보완] Tcp Ip Socket 소켓 통신 클라이언트 모듈 - 데이터 송수신 중 서버 소켓 종료 대응 본문
투케이2K 유틸파일
184. (TWOK/UTIL) [Android/Java] [기능 보완] Tcp Ip Socket 소켓 통신 클라이언트 모듈 - 데이터 송수신 중 서버 소켓 종료 대응
투케이2K 2026. 3. 30. 19:12728x90
반응형
[설 명]
프로그램 : Mobile / Android
설 명 : [Android/Java] [기능 보완] Tcp Ip Socket 소켓 통신 클라이언트 모듈 - 데이터 송수신 중 서버 소켓 종료 대응

[소스 코드]
-----------------------------------------------------------------------------------------
[사전 설명 및 설정 사항]
-----------------------------------------------------------------------------------------
- 개발 환경 : Mobile / Android
- 개발 기술 : Tcp Ip / Socket / Client
- 사전) 👉 TCP/IP 소켓 통신 간략 설명 :
>> TCP/IP 소켓 통신은 네트워크에서 프로그램 간에 데이터를 주고받기 위한 기본적인 통신 방식입니다.
- TCP (Transmission Control Protocol) → 연결 기반, 신뢰성 보장, 순서 보장
- IP (Internet Protocol) → 패킷을 목적지로 전달하는 역할
>> 소켓은 쉽게 말하면 네트워크 통신을 하기 위한 문 (door) 입니다. (소켓 = 네트워크에서 데이터를 주고받기 위한 통신 채널)
>> TCP 소켓 통신의 특징 :
- 연결 기반(Connection-oriented) → Handshake 필요
- 신뢰성 보장 → 패킷 유실 시 재전송
- 순서 보장 → 순서 틀리면 자동으로 재정렬
- 스트림 기반 → 연속된 데이터 흐름
>> TCP 소켓 통신의 구성 요소 :
- IP 주소 : 상대방이 있는 위치
- Port 번호 : 상대방 프로그램의 번호
- Socket : IP + Port로 연결된 통신 객체
- Server Socket : 서버에서 클라이언트의 접속을 기다리는 소켓
-----------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------
[소스 코드]
-----------------------------------------------------------------------------------------
package com.example.javaproject.C_Module;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkInfo;
import com.example.javaproject.S_FinalData;
import com.example.javaproject.S_Log;
import org.json.JSONObject;
import java.io.DataInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashMap;
public class C_TcpIp_Client_Socket_Module {
/**
* // --------------------------------------------------------------------------------------
* TODO [클래스 설명]
* // --------------------------------------------------------------------------------------
* 1. [설명] : TCP/IP 통신 수행 클래스
* // --------------------------------------------------------------------------------------
* */
/**
* // --------------------------------------------------------------------------------------
* TODO [빠른 로직 찾기 : 주석 로직 찾기]
* // --------------------------------------------------------------------------------------
* // [SEARCH FAST] : [기기 등록 요청 실시 >> 응답 결과 확인]
* // --------------------------------------------------------------------------------------
*
* // --------------------------------------------------------------------------------------
*/
// ------------------------------------------------------------------------------------------
// TODO [사용 방법]
// ------------------------------------------------------------------------------------------
/*
try {
// -------------------------------------------------
// TODO [1]. 소켓 통신을 하기 위한 IP , PORT 선언
// -------------------------------------------------
String ip = "192.168.0.123";
int port = 5000;
// --------------------------------------
// TODO [2]. [소켓 모듈 클래스 인스턴스 초기화]
// --------------------------------------
C_TcpIp_Client_Socket_Module c_socket_module = C_TcpIp_Client_Socket_Module.getInstance();
c_socket_module.setContext(A_Intro.this);
// --------------------------------------
// TODO [3]. [소켓 연결 수행]
// --------------------------------------
if(c_socket_module.connectHost(ip, port) == true) { // [소켓 연결 상태 확인]
// --------------------------------------
// TODO [4]. [기기 등록 요청 수행]
// --------------------------------------
HashMap<String, Object> deviceRegMap = c_socket_module.request_Device_Reg();
S_Log._W_("소켓 통신 :: 디바이스 등록 요청 수행 결과 확인", new String[]{
"SUCCESS :: " + String.valueOf(deviceRegMap.get(c_socket_module.RETURN_SUCCESS_FLAG))
});
// --------------------------------------
// TODO [5]. [소켓 연결 종료]
// --------------------------------------
c_socket_module.closeSocket();
// --------------------------------------
// TODO [6]. [응답 플래그에 맞게 팝업 표시 및 기기 등록 상태 조회 실시]
// --------------------------------------
if ((boolean)deviceRegMap.get(c_socket_module.RETURN_SUCCESS_FLAG) == true){
}
else {
// [등록 실패]
String errorMessage = "\n소켓 데이터 송수신에 실패 했습니다 ..\n\n["+String.valueOf(deviceRegMap.get(c_socket_module.RETURN_ERROR_MESSAGE))+"]";
}
}
else {
S_Log._E_("소켓 연결 실패", null);
}
}
catch (Exception e) {
S_Log._printStackTrace_(null, S_FinalData.LOG_BUG_STATE, null, e);
}
*/
// ------------------------------------------------------------------------------------------
// ------------------------------------------------------------------------------------------
// TODO [전역 변수 선언]
// ------------------------------------------------------------------------------------------
private String ACTIVITY_NAME = "C_TcpIp_Client_Socket_Module";
private Context mMainCtx; // [컨텍스트]
private Socket mSocket; // [소켓]
private OutputStream mOutputStream; // [스트림]
private PrintWriter mPrintWriter; // [스트림]
private InputStream mInputStream; // [스트림]
private DataInputStream mDataDataInputStream; // [스트림]
public static final String RETURN_SUCCESS_FLAG = "RETURN_SUCCESS_FLAG"; // [리턴 데이터 반환 키 값]
public static final String RETURN_ERROR_MESSAGE = "RETURN_ERROR_MESSAGE"; // [리턴 데이터 반환 키 값]
// ------------------------------------------------------------------------------------------
// TODO [콘텍스트 지정]
// ------------------------------------------------------------------------------------------
public void setContext(Context ctx) {
mMainCtx = ctx;
}
// ------------------------------------------------------------------------------------------
// TODO [인스턴스 생성]
// ------------------------------------------------------------------------------------------
public static C_TcpIp_Client_Socket_Module getInstance() { return C_TcpIp_Client_Socket_Module.LazyHolder.INSTANCE; }
private static class LazyHolder {
private static final C_TcpIp_Client_Socket_Module INSTANCE = new C_TcpIp_Client_Socket_Module();
}
// ------------------------------------------------------------------------------------------
// TODO [소켓 생성 실시]
// ------------------------------------------------------------------------------------------
private synchronized Socket createSocket(String host, int port) {
S_Log._D_(ACTIVITY_NAME + " :: createSocket :: 소켓 생성 수행", new String[]{ "HOST :: " + String.valueOf(host), "PORT :: " + String.valueOf(port) });
ConnectivityManager connectivity = (ConnectivityManager) mMainCtx.getSystemService(Context.CONNECTIVITY_SERVICE);
Socket sock = null;
try{
if (connectivity != null) {
for (Network network : connectivity.getAllNetworks()) { // TODO [연결된 네트워크 확인]
NetworkInfo networkInfo = connectivity.getNetworkInfo(network);
if (networkInfo != null && networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { // TODO [와이파이 연결 상태 체크]
if (networkInfo.isConnected()) {
S_Log._W_(ACTIVITY_NAME + " :: createSocket :: 소켓 생성 성공", new String[]{ "HOST :: " + String.valueOf(host), "PORT :: " + String.valueOf(port) });
// ✅ [소켓 지정 실시]
sock = network.getSocketFactory().createSocket(host, port);
}
}
}
}
else {
S_Log._E_(ACTIVITY_NAME + " :: createSocket :: 소켓 생성 에러", new String[]{ "Error :: ConnectivityManager is null" });
}
} catch (Exception e) {
S_Log._E_(ACTIVITY_NAME + " :: createSocket :: 소켓 생성 에러", new String[]{ "Exception :: " + String.valueOf(e.getMessage()) });
}
return sock;
}
// ------------------------------------------------------------------------------------------
// TODO [디바이스 호스트 연결 실시]
// ------------------------------------------------------------------------------------------
public synchronized boolean connectHost(String host, int port) {
// [연결 상태 체크 변수]
boolean isConnection = false;
// [로직 처리 수행]
try {
// [소켓 연결 수행]
if(this.mSocket != null) { // TODO [소켓이 널이 아닌 경우]
S_Log._E_(ACTIVITY_NAME + " :: connectHost :: 호스트 연결 실패", new String[]{ "설 명 :: 소켓 연결 된 상태 (Socket Not Null)" });
}
else { // TODO [소켓이 널인 경우]
S_Log._D_(ACTIVITY_NAME + " :: connectHost :: 호스트 연결 수행", new String[]{ "HOST :: " + String.valueOf(host), "PORT :: " + String.valueOf(port) });
this.mSocket = createSocket(host, port); // [소켓 생성]
// -----------------------------------------
// TODO [소켓 연결 끊김 버그로 설정 해제]
// -----------------------------------------
/**
* W/System.err: java.net.SocketException: Software caused connection abort
* W/System.err: at java.net.SocketInputStream.socketRead0(Native Method)
* W/System.err: at java.net.SocketInputStream.socketRead(SocketInputStream.java:118)
* W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:173)
* W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:143)
* W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:129)
* W/System.err: at maincp.android.uis.MainCP.Main_SensorGuardView.SensorGuardClientSocketModule.request_Device_Reg(SensorGuardClientSocketModule.java:449)
* W/System.err: at maincp.android.uis.MainCP.Main_SensorGuardView.SensorGuardRegHubViewActivity$10$1.run(SensorGuardRegHubViewActivity.java:1352)
* */
//this.mSocket.setTcpNoDelay(true);
//this.mSocket.setSoTimeout(0);
// -----------------------------------------
isConnection = this.mSocket.isConnected(); // [소켓 연결 상태 확인]
if (isConnection == true){
S_Log._W_(ACTIVITY_NAME + " :: connectHost :: 호스트 연결 성공", new String[]{ "설 명 :: 데이터 송수신을 위한 스트림 설정" });
// ✅ [데이터 송수신 설정]
this.mOutputStream = this.mSocket.getOutputStream(); // [읽기]
this.mPrintWriter = new PrintWriter(mOutputStream);
this.mInputStream = this.mSocket.getInputStream(); // [쓰기]
this.mDataDataInputStream = new DataInputStream(mInputStream);
}
else {
S_Log._E_(ACTIVITY_NAME + " :: connectHost :: 호스트 연결 실패", new String[]{ "설 명 :: mSocket.isConnected false" });
}
}
}
catch (Exception e){
S_Log._printStackTrace_(null, S_FinalData.LOG_BUG_STATE, null, e);
// [Exception 발생 시 소켓 연결 종료]
closeSocket();
}
// [리턴 반환 수행]
return isConnection;
}
// ------------------------------------------------------------------------------------------
// TODO [소켓 연결 종료]
// ------------------------------------------------------------------------------------------
public synchronized void closeSocket() {
try {
// [생성된 소켓이 있는 경우 종료 및 스트림 닫기]
if(this.mPrintWriter != null) {
try {
this.mPrintWriter.close();
this.mPrintWriter = null;
}
catch(Exception err){ }
S_Log.e("KWON_TWOK", "closeSocket >> mPrintWriter.close()");
}
if(this.mDataDataInputStream != null) {
try {
this.mDataDataInputStream.close();
this.mDataDataInputStream = null;
}
catch(Exception err){ }
S_Log.e("KWON_TWOK", "closeSocket >> mDataDataInputStream.close()");
}
if(this.mOutputStream != null) {
try {
this.mOutputStream.close();
this.mOutputStream = null;
}
catch(Exception err){ }
S_Log.e("KWON_TWOK", "closeSocket >> mOutputStream.close()");
}
if(this.mInputStream != null) {
try {
this.mInputStream.close();
this.mInputStream = null;
}
catch(Exception err){ }
S_Log.e("KWON_TWOK", "closeSocket >> mInputStream.close()");
}
if(this.mSocket != null) {
try {
this.mSocket.close();
boolean isClose = this.mSocket.isClosed();
this.mSocket = null;
S_Log.e("KWON_TWOK", "closeSocket >> mSocket.close() : " + String.valueOf(isClose));
}
catch(Exception err){
S_Log.e("KWON_TWOK", "closeSocket >> mSocket.close() : Exception : " + String.valueOf(err.getMessage()));
}
}
}
catch (Exception e) {
S_Log._printStackTrace_(null, S_FinalData.LOG_BUG_STATE, null, e);
}
S_Log._E_(ACTIVITY_NAME + " :: closeSocket :: 소켓 연결 종료 수행", null);
}
// ------------------------------------------------------------------------------------------
// TODO [SEARCH FAST] : [기기 등록 요청 실시 >> 응답 결과 확인]
// ------------------------------------------------------------------------------------------
public synchronized HashMap request_Device_Reg() {
S_Log._D_(ACTIVITY_NAME + " :: request_Device_Reg :: 기기 등록 요청 수행", null);
/**
* // ----------------------------------------
* TODO [REQUEST] : [APP >> DEVICE]
* // ----------------------------------------
*
* {
* "reg_name" : "TOWK"
* }
*
* // ----------------------------------------
* */
/**
* // ----------------------------------------
* TODO [RESPONSE] : [DEVICE >> APP]
* // ----------------------------------------
*
* {
* "result" : true
* }
*
* // ----------------------------------------
* */
// -----------------------------------------------
// [리턴 변수 선언]
// -----------------------------------------------
HashMap<String, Object> returnData = new HashMap<>();
// -----------------------------------------------
// [로직 처리 수행]
// -----------------------------------------------
try {
// -----------------------------------------
// TODO [1]. [APP TO DEVICE : 디바이스 등록 요청 실시]
// -----------------------------------------
JSONObject reqJson = new JSONObject();
reqJson.put("reg_name", "TWOK");
String requestData = reqJson.toString();
S_Log._D_(ACTIVITY_NAME + " :: request_Device_Reg :: [요청] :: [APP] >> [DEVICE] :: 기기 등록 요청 수행", new String[]{ "REQUEST :: " + requestData.toString() });
mPrintWriter.write(requestData); // ✅ [데이터 전송]
mPrintWriter.flush();
// -----------------------------------------
// -----------------------------------------
// TODO [2]. [DEVICE TO APP : 디바이스 정보 응답 확인 실시]
// -----------------------------------------
int len = 0;
byte[] buffer = new byte[6144]; // 응답 메시지 수신 버퍼
if(mInputStream != null){ // ✅ 응답 메시지 확인
len = mInputStream.read(buffer);
}
byte[] subBuffer = new byte[len];
System.arraycopy(buffer, 0, subBuffer,0, len);
// [byte to string 변환]
String jsonString = new String(subBuffer);
jsonString = jsonString.replaceAll(" ", "");
S_Log._D_(ACTIVITY_NAME + " :: request_Device_Reg :: [응답] :: [DEVICE] >> [APP] :: 기기 등록 응답 확인", new String[]{ "RESPONSE :: " + jsonString.toString() });
// ✅ [리턴 데이터 삽입]
returnData.put(RETURN_SUCCESS_FLAG, true);
returnData.put(RETURN_ERROR_MESSAGE, "");
// -----------------------------------------
}
catch (Exception e){
S_Log._printStackTrace_(null, S_FinalData.LOG_BUG_STATE, null, e);
// ---------------------------------------------------
// TODO [Exception] : [예외 허용 처리]
// ---------------------------------------------------
// TODO 간헐적 디바이스 장비가 Response 응답을 주지 않고 서버 종료 시킨 경우 (앱에서 넘긴 데이터는 다받은 상태)
// ---------------------------------------------------
if(e instanceof SocketException && String.valueOf(e.getMessage()).contains("Software caused connection abort")){
S_Log._W_(ACTIVITY_NAME + " :: request_Device_Reg :: 간헐적 디바이스 장비가 Response 응답을 주지 않고 서버 종료 시킨 경우 Exception 예외 허용 처리", null);
// ✅ [리턴 데이터 삽입]
returnData.put(RETURN_SUCCESS_FLAG, true);
returnData.put(RETURN_ERROR_MESSAGE, "");
}
else {
// ❌ [에러 발생 데이터 삽입]
returnData.put(RETURN_SUCCESS_FLAG, false);
returnData.put(RETURN_ERROR_MESSAGE, String.valueOf(e.getMessage()));
}
}
// [리턴 반환 실시]
return returnData;
}
} // TODO [클래스 종료]
728x90
반응형
'투케이2K 유틸파일' 카테고리의 다른 글
Comments
