투케이2K

145. (TWOK/UTIL) [Ios/Swift] C_TcpIp_NWConnection_Client_Socket_Module : TCP IP 소켓 통신 모듈 본문

투케이2K 유틸파일

145. (TWOK/UTIL) [Ios/Swift] C_TcpIp_NWConnection_Client_Socket_Module : TCP IP 소켓 통신 모듈

투케이2K 2024. 12. 6. 18:05

[설 명]

프로그램 : Ios / Swift

설 명 : C_TcpIp_NWConnection_Client_Socket_Module : TCP IP 소켓 통신 모듈

 

[소스 코드]

 

import Foundation
import UIKit
// -----------------------------------------
//MARK: [네트워크 소켓 통신 사용]
import Network
// -----------------------------------------

class C_TcpIp_NWConnection_Client_Socket_Module {



    /**
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * TODO [클래스 설명]
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 1. TCP IP 소켓 통신 클라이언트 모듈
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 2. NWConnection : ios 12 이상 부터 사용 가능한 애플에서 지원하는 네트워크 프레임 워크입니다
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 3. NWConnection 는 로컬 엔드포인트와 원격 엔드포인트 간의 양방향 데이터 연결 (TCP , UDP) 을 수행할 수 있습니다
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 4. NWConnection 를 사용하기 위해서는 import Network 패키지 호출 정의가 필요합니다
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 5. NWParameters 설정 가능 옵션 : tls , tcp , dtls , udp , quic , quicDatagram
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 6. 애플 공식 참고 사이트 : https://developer.apple.com/documentation/network/nwconnection
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * 7. NWProtocolTCP.Options 사용 가능 버전 :
     *
     * >> iOS 12.0 이상
     * >> 아이패드 OS 12.0+
     * >> 맥 카탈리스트 12.0+
     * >> 맥 OS 10.14+
     * >> tvOS 12.0+
     * >> 비전 OS 1.0+
     * >> 워치OS 5.0+
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * */





    /**
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * //  TODO [빠른 로직 찾기 : 주석 로직 찾기]
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : observableSocketConnect : IP , PORT 사용해 소켓 연결 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : closeSocketConnect : 소켓 연결 종료 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : receiveData : 실시간 소켓 메시지 수신 상태 확인
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * [SEARCH FAST] : observableSendData : 실시간 소켓 메시지 전송 수행
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     *
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * */
    
    
    
    
    
    
    /**
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * TODO [소스 코드 사용 방법]
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     DispatchQueue.main.async { // [비동기 요청]
         
         // [변수 선언 수행]
         let ip = "192.168.0.10"
         let port = 18501
         
         
         // [소켓 연결 실시]
         C_TcpIp_NWConnection_Client_Socket_Module().observableSocketConnect(ip: ip, port: UInt16(port)){(connectResult) in
             
             S_Log._F_(description: "소켓 연결 확인 수행", data: ["\(connectResult)"])

             if connectResult == true {
                 
                 
                 // [실시간 메시지 전송 수행]

                 DispatchQueue.main.asyncAfter(deadline: .now() + 5) { // [5초 시간 설정]
                  
                     C_TcpIp_NWConnection_Client_Socket_Module().observableSendData(msg: "hello"){(sendResult) in
                         
                         S_Log._F_(description: "소켓 실시간 메시지 전송 확인", data: ["\(sendResult)"])
                         
                     }
                     
                 }
                 
             }
             else {
                S_Log._F_(description: "소켓 연결 에러 메시지", data: ["\(C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG)"])
             }
             
         }
     }
     * // -----------------------------------------------------------------------------------------------------------------------------------------------------------------
     * */
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [전역 변수 선언]
    // -----------------------------------------------------------------------------------------
    private static let ACTIVITY_NAME = "C_TcpIp_NWConnection_Client_Socket_Module"
    
    let CONNECT_TIME_OUT = 20.0 // [연결 타임 아웃 시간]
    
    lazy var tcpOptions: NWProtocolTCP.Options = {
        let options = NWProtocolTCP.Options()
        options.noDelay = true // [딜레이 비활성]
        options.connectionTimeout = Int(self.CONNECT_TIME_OUT) // [connection timed out]
        return options
    }()

    lazy var parames: NWParameters = {
        let parames = NWParameters(tls: nil, tcp: self.tcpOptions)
        if let isOption = parames.defaultProtocolStack.internetProtocol as? NWProtocolIP.Options {
            isOption.version = .v4 // [ipv4 방식 : 192.168.1.1]
        }
        parames.preferNoProxies = true
        return parames
    }()
    
    static var connection: NWConnection? = nil // [소켓 통신 수행 객체]
    var workItem: DispatchWorkItem? = nil // [연결 타임 아웃 핸들러]
    static var connectFlag = false // [연결 완료 플래그 값]
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : observableSocketConnect : IP , PORT 사용해 소켓 연결 수행
    // -----------------------------------------------------------------------------------------
    static var SOCKET_CONNECT_LOG = ""
    func observableSocketConnect(ip: String, port: UInt16, completion: @escaping (Bool)->()) {
        
        /*
        // -----------------------------------------
        [observableSocketConnect 메소드 설명]
        // -----------------------------------------
        1. IP , PORT 사용해 소켓 연결 수행
        // -----------------------------------------
        2. 호출 방법 :
         
         C_TcpIp_NWConnection_Client_Socket_Module().observableSocketConnect(ip: "192.168.1.1", port: 5000){(connectResult) in
             
             S_Log._F_(description: "소켓 연결 확인 수행", data: ["\(connectResult)"])

             if connectResult == true {
                
                // [소켓 연결 완료 로직 처리]
             }
             else {
                S_Log._F_(description: "소켓 연결 에러 메시지", data: ["\(C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG)"])
             }
             
         }
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */


        // [변수 선언]
        C_TcpIp_NWConnection_Client_Socket_Module.connection = nil
        C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG = ""
        self.workItem = nil
        C_TcpIp_NWConnection_Client_Socket_Module.connectFlag = false
        
        
        // [로직 처리 수행]
        DispatchQueue.main.async {
            S_Log._D_(description: "소켓 생성 및 연결 수행", data: [ "IP :: \(ip)", "PORT :: \(port)" ])
            
            
            // [인풋 데이터 널 체크]
            if C_Util().stringNotNull(str: ip) == true && port >= 0 {
                
                // ---------------------------------------------
                // MARK: [소켓 연결 및 연결 상태 확인]
                // ---------------------------------------------
                //C_TcpIp_NWConnection_Client_Socket_Module.connection = NWConnection(host: NWEndpoint.Host(ip), port: NWEndpoint.Port("\(port)")!, using: .tcp)
                C_TcpIp_NWConnection_Client_Socket_Module.connection = NWConnection(host: NWEndpoint.Host(ip), port: NWEndpoint.Port("\(port)")!, using: self.parames)

                // [연결 상태 업데이트 핸들러 설정]
                C_TcpIp_NWConnection_Client_Socket_Module.connection?.stateUpdateHandler = { state in
                    switch state {
                    case .ready:
                        C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG = "[Success] : Connection Ready State"
                        C_TcpIp_NWConnection_Client_Socket_Module.connectFlag = true
                        
                        S_Log._W_(description: "소켓 생성 및 연결 성공", data: [
                            "M_LOG :: \(C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG)",
                            "IP :: \(ip)",
                            "PORT :: \(port)"
                        ])
                        
                        // ---------------------------------------------
                        // MARK: [실시간 소켓 메시지 수신 상태 확인]
                        // ---------------------------------------------
                        self.receiveData()
                        
                        // [콜백 반환]
                        completion(true)
                        return
                        
                    case .failed(let error):
                        C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG = "[Fail] : Connection Fail State"
                        
                        S_Log._E_(description: "소켓 생성 및 연결 실패", data: [
                            "M_LOG :: \(C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG)",
                            "Description :: \(error)"
                        ])
                        
                        // [콜백 반환]
                        if C_TcpIp_NWConnection_Client_Socket_Module.connectFlag == false {
                         
                            completion(false)
                            
                        }
                        
                        // [객체 초기화]
                        if C_TcpIp_NWConnection_Client_Socket_Module.connection != nil {
                            
                            C_TcpIp_NWConnection_Client_Socket_Module.connection = nil
                            C_TcpIp_NWConnection_Client_Socket_Module.connectFlag = false
                            
                        }
                        
                        return
                        
                    case .cancelled:
                        C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG = "[Cancel] : Connection Cancel State"
                        
                        S_Log._E_(description: "소켓 생성 및 연결 실패", data: [
                            "M_LOG :: \(C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG)"
                        ])
                        
                        // [콜백 반환]
                        if C_TcpIp_NWConnection_Client_Socket_Module.connectFlag == false {
                         
                            completion(false)
                            
                        }
                        
                        // [객체 초기화]
                        if C_TcpIp_NWConnection_Client_Socket_Module.connection != nil {
                            
                            C_TcpIp_NWConnection_Client_Socket_Module.connection = nil
                            C_TcpIp_NWConnection_Client_Socket_Module.connectFlag = false
                            
                        }
                        
                        return
                        
                    default:
                        break
                    }
                }

                
                // [연결 시작]
                C_TcpIp_NWConnection_Client_Socket_Module.connection?.start(queue: .global())
                
                
                // ---------------------------------------------
                // MARK: [소켓 연결 타임 아웃 처리]
                // ---------------------------------------------
                self.workItem = DispatchWorkItem {
                    
                    if C_TcpIp_NWConnection_Client_Socket_Module.connection != nil && C_TcpIp_NWConnection_Client_Socket_Module.connectFlag == false {
                        
                        C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG = "[Time Out] : Socket Connection TimeOut"
                        
                        S_Log._E_(description: "소켓 생성 및 연결 실패", data: [
                            "M_LOG :: \(C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG)"
                        ])
                        
                        // [TCP 연결 취소]

                        C_TcpIp_NWConnection_Client_Socket_Module.connection?.cancel()
                        
                    }
                    
                }
                
                let delay = DispatchTime.now() + self.CONNECT_TIME_OUT // [특정 시간 후에 실행]
                
                DispatchQueue.main.asyncAfter(deadline: delay, execute: self.workItem!)
                
            }
            else {
                C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG = "[Error] : Input Data Is Null"
                
                S_Log._E_(description: "소켓 생성 및 연결 에러", data: [
                    "M_LOG :: \(C_TcpIp_NWConnection_Client_Socket_Module.SOCKET_CONNECT_LOG)"
                ])
                completion(false) // [콜백 반환]
                return
                
            }
        }
        
    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : closeSocketConnect : 소켓 연결 종료 수행
    // -----------------------------------------------------------------------------------------
    func closeSocketConnect() {
        
        if C_TcpIp_NWConnection_Client_Socket_Module.connection != nil {
            S_Log._E_(description: "소켓 연결 종료 수행 [IF]", data: nil)
            
            C_TcpIp_NWConnection_Client_Socket_Module.connection?.cancel()
            C_TcpIp_NWConnection_Client_Socket_Module.connection = nil
            C_TcpIp_NWConnection_Client_Socket_Module.connectFlag = false
        }
        else {
            S_Log._E_(description: "소켓 연결 종료 수행 [ELSE]", data: nil)
        }
        
    }
    
    
    
    
    
    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : receiveData : 실시간 소켓 메시지 수신 상태 확인
    // -----------------------------------------------------------------------------------------
    static var RECEIVE_ERROR_LOG = ""
    private func receiveData() {
        
        if C_TcpIp_NWConnection_Client_Socket_Module.connection != nil {
            S_Log._D_(description: "소켓 실시간 메시지 수신 감지 수행", data: nil)
            
            C_TcpIp_NWConnection_Client_Socket_Module.connection?.receive(minimumIncompleteLength: 1, maximumLength: 1024, completion: { data, _, isComplete, error in
                
                // ---------------------------------------------
                // MARK: [실시간 메시지 수신 확인]
                // ---------------------------------------------
                if let data = data, !data.isEmpty {
                    let message = String(data: data, encoding: .utf8) ?? ""
                    
                    S_Log._W_(description: "[Ing] ---- [소켓 실시간 메시지 수신 감지] ---- [Ing]", data: [
                        "message :: \(message)"
                    ])
                    
                    
                    // ---------------------------------------------
                    // MARK: [로직 분기 처리]
                    // ---------------------------------------------
                    
                }

                
                // ---------------------------------------------
                // MARK: [계속해서 실시간 메시지 수신 처리]
                // ---------------------------------------------
                if isComplete {
                    C_TcpIp_NWConnection_Client_Socket_Module.RECEIVE_ERROR_LOG = "[Error] : Connection closed by server"
                    
                    S_Log._E_(description: "소켓 실시간 메시지 수신 감지 에러", data: [
                        "M_LOG :: \(C_TcpIp_NWConnection_Client_Socket_Module.RECEIVE_ERROR_LOG)"
                    ])
                    
                    // ---------------------------------------------
                    // MARK: [소켓 연결 종료 및 객체 초기화]
                    // ---------------------------------------------
                    C_TcpIp_NWConnection_Client_Socket_Module.connection?.cancel()
                    //C_TcpIp_NWConnection_Client_Socket_Module.connection = nil
                    //C_TcpIp_NWConnection_Client_Socket_Module.connectFlag = false
                    
                } else if let error = error {
                    C_TcpIp_NWConnection_Client_Socket_Module.RECEIVE_ERROR_LOG = "[Error] : let error catch"
                    
                    S_Log._E_(description: "소켓 실시간 메시지 수신 감지 에러", data: [
                        "M_LOG :: \(C_TcpIp_NWConnection_Client_Socket_Module.RECEIVE_ERROR_LOG)",
                        "Description :: \(error)"
                    ])
                    
                    // ---------------------------------------------
                    // MARK: [소켓 연결 종료 및 객체 초기화]
                    // ---------------------------------------------
                    C_TcpIp_NWConnection_Client_Socket_Module.connection?.cancel()
                    //C_TcpIp_NWConnection_Client_Socket_Module.connection = nil
                    //C_TcpIp_NWConnection_Client_Socket_Module.connectFlag = false
                    
                } else {
                    
                    // ---------------------------------------------
                    // [계속해서 데이터 수신]
                    // ---------------------------------------------
                    self.receiveData()
                    
                }
            })
            
        }
        else {
            S_Log._E_(description: "소켓 실시간 메시지 수신 감지 에러 :: connection is null", data: nil)
        }
        
    }
    
    
    

    
    // -----------------------------------------------------------------------------------------
    // MARK: - [SEARCH FAST] : observableSendData : 실시간 소켓 메시지 전송 수행
    // -----------------------------------------------------------------------------------------
    static var SEND_ERROR_LOG = ""
    func observableSendData(msg:String, completion: @escaping (Bool)->()) {
        
        /*
        // -----------------------------------------
        [observableSendData 메소드 설명]
        // -----------------------------------------
        1. 실시간 소켓 메시지 전송 수행
        // -----------------------------------------
        2. 호출 방법 :
         
         C_TcpIp_NWConnection_Client_Socket_Module().observableSendData(msg: "hello"){(sendResult) in
             
             S_Log._F_(description: "소켓 실시간 메시지 전송 확인", data: ["\(sendResult)"])

             if sendResult == true {
                
             }
             else {
                S_Log._F_(description: "소켓 실시간 메시지 전송 에러 메시지", data: ["\(C_TcpIp_NWConnection_Client_Socket_Module.SEND_ERROR_LOG)"])
             }
             
         }
         
        // -----------------------------------------
        3. 필요 import :
         
         import Network
        // -----------------------------------------
        */
        
        
        // [변수 선언]
        C_TcpIp_NWConnection_Client_Socket_Module.SEND_ERROR_LOG = ""
        
        
        // [로직 처리 수행]
        DispatchQueue.global().sync {

            if C_TcpIp_NWConnection_Client_Socket_Module.connection != nil && C_Util().stringNotNull(str: msg) == true {
                
                S_Log._D_(description: "소켓 클라이언트 >> 서버 메시지 전송 수행", data: nil)
                
                // ---------------------------------------------
                // MARK: [String To Byte 데이터 전송 수행]
                // ---------------------------------------------
                let data = msg.data(using: .utf8) ?? Data() // [string to byte]
                
                C_TcpIp_NWConnection_Client_Socket_Module.connection?.send(content: data, completion: .contentProcessed { error in
                    if let error = error {
                        C_TcpIp_NWConnection_Client_Socket_Module.SEND_ERROR_LOG = "[Error] : Socket Send Message Error"
                        
                        S_Log._E_(description: "소켓 실시간 메시지 전송 에러", data: [
                            "M_LOG :: \(C_TcpIp_NWConnection_Client_Socket_Module.SEND_ERROR_LOG)",
                            "Description :: \(error)"
                        ])
                        completion(false) // [콜백 반환]
                        return
                        
                    } else {
                        S_Log._W_(description: "소켓 실시간 메시지 전송 성공", data: [
                            "msg :: \(msg)"
                        ])
                        completion(true) // [콜백 반환]
                        return
                        
                    }
                })
                
            }
            else {
                C_TcpIp_NWConnection_Client_Socket_Module.SEND_ERROR_LOG = "[Error] : Input Send Message Is Null"
                
                S_Log._E_(description: "소켓 실시간 메시지 전송 에러", data: [
                    "M_LOG :: \(C_TcpIp_NWConnection_Client_Socket_Module.SEND_ERROR_LOG)"
                ])
                completion(false) // [콜백 반환]
                return
            }
            
        }

    }

    
} // [클래스 종료]

 

반응형
Comments