Notice
Recent Posts
Recent Comments
Link
투케이2K
582. (ios/swift5) [간단 소스] NWConnection 사용해 FTP 연결 및 USER , PASS 사용자 인증 수행 방법 본문
IOS
582. (ios/swift5) [간단 소스] NWConnection 사용해 FTP 연결 및 USER , PASS 사용자 인증 수행 방법
투케이2K 2024. 12. 1. 00:46[개발 환경 설정]
개발 툴 : XCODE
개발 언어 : SWIFT5
[소스 코드]
// --------------------------------------------------------------------------------------
[개발 및 테스트 환경]
// --------------------------------------------------------------------------------------
- 언어 : Swift
- 개발 툴 : Xcode
- NWConnection 설명 :
>> NWConnection 는 로컬 엔드포인트와 원격 엔드포인트 간의 양방향 데이터 연결 (TCP , UDP) 을 수행할 수 있습니다
>> NWConnection 를 사용하기 위해서는 import Network 패키지 호출 정의가 필요합니다
>> NWParameters 설정 가능 옵션 :
- tls
- tcp
- dtls
- udp
- quic
- quicDatagram
// --------------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------
[소스 코드]
// --------------------------------------------------------------------------------------
// ------------------------------------------------------------
// MARK: - [전역 변수 선언]
// ------------------------------------------------------------
private static let ACTIVITY_NAME = "C_FTP_NWConnection_Client_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 // [FTP 통신 수행 객체]
var workItem: DispatchWorkItem? = nil // [연결 타임 아웃 핸들러]
static var fileNwconnection: NWConnection? = nil // [파일 다운로드 통신 객체]
static var connectFlag = false // MARK: [FTP 연결 및 로그인 수행 완료 플래그 값]
static var downloadFlag = false // MARK: [FTP 파일 다운로드 완료 플래그 값]
static var FTP_SERTVER = "" // [지속 사용]
static var FTP_PORT = 0 // [지속 사용]
static var FTP_USER_NAME = "" // [지속 사용]
static var FTP_USER_PW = "" // [지속 사용]
// ------------------------------------------------------------
// MARK: - [SEARCH FAST] : observableFtpConnect : FTP 연결 수행
// ------------------------------------------------------------
// 1. 사용자 FPT 서버 활성 접속 상태 확인
// ------------------------------------------------------------
// 2. USER 커맨드를 사용해 사용자 ID 인증 요청
// ------------------------------------------------------------
// 3. PASS 커맨드를 사용해 사용자 PW 인증 요청
// ------------------------------------------------------------
static var FTP_CONNECT_LOG = ""
static var connectOperationQueue = OperationQueue()
func observableFtpConnect(server: String, port: UInt16, userName: String, pw: String, completion: @escaping (Bool)->()) {
/*
// -----------------------------------------
[observableFtpConnect 메소드 설명]
// -----------------------------------------
1. 도메인, 사용자 정보 사용해 FTP 연결 수행
// -----------------------------------------
2. 호출 방법 : MARK: [FTP 포트는 21 번 포트]
C_FTP_NWConnection_Client_Module().observableFtpConnect(server: "towk.test.co.kr", port: UInt16(21), userName: "twok123", pw: "twok0123456789"){(connectResult) in
S_Log._F_(description: "FTP 연결 확인 수행", data: ["\(connectResult)"])
if connectResult == true {
// [FTP 연결 완료 로직 처리]
}
else {
S_Log._F_(description: "FTP 연결 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"])
}
}
// -----------------------------------------
3. 필요 import :
import Network
// -----------------------------------------
*/
// [변수 선언 및 초기화]
C_FTP_NWConnection_Client_Module.connection = nil
C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = ""
self.workItem = nil
C_FTP_NWConnection_Client_Module.connectFlag = false // MARK: [최종 서버 접속 및 로그인 성공 플래그 처리 변수]
C_FTP_NWConnection_Client_Module.FTP_SERTVER = ""
C_FTP_NWConnection_Client_Module.FTP_PORT = 0
C_FTP_NWConnection_Client_Module.FTP_USER_NAME = ""
C_FTP_NWConnection_Client_Module.FTP_USER_PW = ""
// MARK: [작업 큐에 추가]
C_FTP_NWConnection_Client_Module.connectOperationQueue.isSuspended = true
let block = { completion(C_FTP_NWConnection_Client_Module.connectFlag) }
C_FTP_NWConnection_Client_Module.connectOperationQueue.addOperation(block)
// [로직 처리 수행]
DispatchQueue.main.async {
S_Log._D_(description: "FTP 연결 수행", data: [ "SERVER :: \(server)", "PORT :: \(port)", "USER_NAME :: \(userName)", "PW :: \(pw)" ])
// [인풋 데이터 널 체크]
if C_Util().stringNotNull(str: server) == true && port >= 0
&& C_Util().stringNotNull(str: userName) == true && C_Util().stringNotNull(str: pw) == true {
// ---------------------------------------------
// MARK: [전역 변수 지정 수행]
// ---------------------------------------------
var loginUrl = ""
C_FTP_NWConnection_Client_Module.FTP_SERTVER = server
C_FTP_NWConnection_Client_Module.FTP_PORT = Int(port)
//C_FTP_NWConnection_Client_Module.FTP_USER_NAME = userName.addingPercentEncoding(withAllowedCharacters: .urlUserAllowed) ?? ""
//C_FTP_NWConnection_Client_Module.FTP_USER_PW = pw.addingPercentEncoding(withAllowedCharacters: .urlPasswordAllowed) ?? ""
C_FTP_NWConnection_Client_Module.FTP_USER_NAME = userName
C_FTP_NWConnection_Client_Module.FTP_USER_PW = pw
// ---------------------------------------------
// MARK: [FTP 접속 URL 형식 지정 및 연결 요청 수행]
// ---------------------------------------------
// MARK: ftp://username:password@ftp.example.com:21
// ---------------------------------------------
loginUrl = "ftp://\(userName.addingPercentEncoding(withAllowedCharacters: .urlUserAllowed) ?? ""):\(pw.addingPercentEncoding(withAllowedCharacters: .urlPasswordAllowed) ?? "")@\(server):\(port)"
// [FTP 연결 옵션 지정]
C_FTP_NWConnection_Client_Module.connection = NWConnection(to: .url(URL(string: loginUrl)!), using: self.parames)
// [연결 상태 업데이트 핸들러 설정]
C_FTP_NWConnection_Client_Module.connection?.stateUpdateHandler = { state in
switch state {
case .ready:
C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Success] : Connection Ready State"
S_Log._D_(description: "FTP 연결 성공", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)",
"loginUrl :: \(loginUrl)"
])
// ---------------------------------------------
// MARK: [실시간 메시지 수신 상태 확인]
// ---------------------------------------------
// MARK: [receiveData 에서 사용자 로그인 처리 까지 완료 후 콜백 반환 수행]
// ---------------------------------------------
self.receiveData()
case .failed(let error):
C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Fail] : Connection Fail State"
S_Log._D_(description: "FTP 연결 실패", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)",
"Description :: \(error)"
])
// [콜백 반환]
if C_FTP_NWConnection_Client_Module.connectFlag == false {
C_FTP_NWConnection_Client_Module.connectOperationQueue.isSuspended = false
}
// [객체 초기화]
if C_FTP_NWConnection_Client_Module.connection != nil {
C_FTP_NWConnection_Client_Module.connection = nil
C_FTP_NWConnection_Client_Module.connectFlag = false
}
return
case .cancelled:
C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Cancel] : Connection Cancel State"
S_Log._D_(description: "FTP 연결 실패", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"
])
// [콜백 반환]
if C_FTP_NWConnection_Client_Module.connectFlag == false {
C_FTP_NWConnection_Client_Module.connectOperationQueue.isSuspended = false
}
// [객체 초기화]
if C_FTP_NWConnection_Client_Module.connection != nil {
C_FTP_NWConnection_Client_Module.connection = nil
C_FTP_NWConnection_Client_Module.connectFlag = false
}
return
default:
break
}
}
// [연결 시작]
C_FTP_NWConnection_Client_Module.connection?.start(queue: .global())
// ---------------------------------------------
// MARK: [FTP 연결 타임 아웃 처리]
// ---------------------------------------------
self.workItem = DispatchWorkItem {
if C_FTP_NWConnection_Client_Module.connection != nil && C_FTP_NWConnection_Client_Module.connectFlag == false {
C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Time Out] : FTP Connection TimeOut"
S_Log._D_(description: "FTP 연결 실패", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"
])
// [FTP 연결 취소]
C_FTP_NWConnection_Client_Module.connection?.cancel()
}
}
let delay = DispatchTime.now() + self.CONNECT_TIME_OUT // [특정 시간 후에 실행]
DispatchQueue.main.asyncAfter(deadline: delay, execute: self.workItem!)
}
else {
C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Error] : Input Data Is Null"
S_Log._D_(description: "FTP 연결 에러", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"
])
// [콜백 반환]
C_FTP_NWConnection_Client_Module.connectOperationQueue.isSuspended = false
return
}
}
}
// ------------------------------------------------------------
// MARK: - [SEARCH FAST] : receiveData : 실시간 메시지 수신 상태 확인
// ------------------------------------------------------------
static var RECEIVE_ERROR_LOG = ""
private func receiveData() {
if C_FTP_NWConnection_Client_Module.connection != nil {
S_Log._D_(description: "RECEIVE 실시간 메시지 수신 감지 수행", data: nil)
C_FTP_NWConnection_Client_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._D_(description: "[Ing] ---- [RECEIVE 실시간 메시지 수신 감지] ---- [Ing]", data: [
"message :: \(message)"
])
// ---------------------------------------------
// MARK: [220] : [로직 분기 처리] : FTP 서버 준비 완료 상태
// ---------------------------------------------
if message.trim().startsWith(_string: "220") == true {
// MARK: [220 FTP Server ready.]
S_Log._D_(description: "FTP 서버 준비 완료 상태 확인", data: [
"message :: \(message)"
])
// MARK: [FTP 로그인 사용자 인증 수행 실시]
C_FTP_NWConnection_Client_Module().observableUserAuth(){(sendResult) in
S_Log._F_(description: "FTP 로그인 사용자 ID 인증 수행 확인", data: ["\(sendResult)"])
if sendResult == true {
}
else {
S_Log._F_(description: "FTP 로그인 사용자 ID 인증 수행 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG)"])
// [로그인 실패 콜백 처리]
self.loginCallbackReturn(returnValue: false)
}
}
}
// ---------------------------------------------
// MARK: [331] : [로직 분기 처리] : 사용자의 암호를 입력 하십시오
// ---------------------------------------------
if message.trim().startsWith(_string: "331") == true {
// MARK: [331 사용자의 암호를 입력 하십시오.] : 사용자 ID 인증 성공
S_Log._D_(description: "FTP 서버 사용자 인증 완료 상태 확인", data: [
"message :: \(message)"
])
// MARK: [FTP 로그인 사용자 PW 확인 실시]
C_FTP_NWConnection_Client_Module().observablePwAuth(){(sendResult) in
S_Log._F_(description: "FTP 로그인 사용자 PW 인증 수행 확인", data: ["\(sendResult)"])
if sendResult == true {
}
else {
S_Log._F_(description: "FTP 로그인 사용자 PW 인증 수행 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG)"])
// [로그인 실패 콜백 처리]
self.loginCallbackReturn(returnValue: false)
}
}
}
// ---------------------------------------------
// MARK: [530] : [로직 분기 처리] : 로그인에 실패했습니다
// ---------------------------------------------
if message.trim().startsWith(_string: "530") == true {
// MARK: [530 로그인에 실패했습니다.] : 변수 초기화
S_Log._D_(description: "FTP 서버 ID, PW 인증 실패 상태 확인", data: [
"message :: \(message)"
])
// [로그인 실패 콜백 처리]
self.loginCallbackReturn(returnValue: false)
}
// ---------------------------------------------
// MARK: [230] : [로직 분기 처리] : 사용자 로그인 성공
// ---------------------------------------------
if message.trim().startsWith(_string: "230") == true {
// MARK: [230 사용자 로그인] : 변수 초기화
S_Log._D_(description: "FTP 서버 ID, PW 인증 성공 상태 확인", data: [
"message :: \(message)"
])
// [로그인 성공 콜백 처리]
self.loginCallbackReturn(returnValue: true)
}
}
// -----------------------------------------------------------------------
// MARK: [계속해서 실시간 메시지 수신 처리]
// -----------------------------------------------------------------------
if isComplete {
C_FTP_NWConnection_Client_Module.RECEIVE_ERROR_LOG = "[Error] : Connection closed by server"
S_Log._D_(description: "RECEIVE 실시간 메시지 수신 감지 에러", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.RECEIVE_ERROR_LOG)"
])
// ---------------------------------------------
// MARK: [소켓 연결 종료 및 객체 초기화]
// ---------------------------------------------
C_FTP_NWConnection_Client_Module.connection?.cancel()
//C_FTP_NWConnection_Client_Module.connection = nil
//C_FTP_NWConnection_Client_Module.connectFlag = false
} else if let error = error {
C_FTP_NWConnection_Client_Module.RECEIVE_ERROR_LOG = "[Error] : let error catch"
S_Log._D_(description: "RECEIVE 실시간 메시지 수신 감지 에러", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.RECEIVE_ERROR_LOG)",
"Description :: \(error)"
])
// ---------------------------------------------
// MARK: [소켓 연결 종료 및 객체 초기화]
// ---------------------------------------------
C_FTP_NWConnection_Client_Module.connection?.cancel()
//C_FTP_NWConnection_Client_Module.connection = nil
//C_FTP_NWConnection_Client_Module.connectFlag = false
} else {
// ---------------------------------------------
// [계속해서 데이터 수신]
// ---------------------------------------------
self.receiveData()
}
})
}
else {
S_Log._D_(description: "소켓 실시간 메시지 수신 감지 에러 :: connection is null", data: nil)
}
}
// ------------------------------------------------------------
// MARK: - [SEARCH FAST] : observableUserAuth : FTP 사용자 ID 인증 요청 상태 확인
// ------------------------------------------------------------
static var LOGIN_USER_ERROR_LOG = ""
func observableUserAuth(completion: @escaping (Bool)->()) {
/*
// -----------------------------------------
[observableUserAuth 메소드 설명]
// -----------------------------------------
1. FTP 사용자 ID 인증 요청 상태 확인
// -----------------------------------------
2. 호출 방법 :
C_FTP_NWConnection_Client_Module().observableUserAuth(){(sendResult) in
S_Log._F_(description: "FTP 로그인 사용자 ID 인증 수행 확인", data: ["\(sendResult)"])
if sendResult == true {
}
else {
S_Log._F_(description: "FTP 로그인 사용자 ID 인증 수행 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG)"])
}
}
// -----------------------------------------
3. 필요 import :
import Network
// -----------------------------------------
*/
// [변수 선언]
C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG = ""
// [로직 처리 수행]
DispatchQueue.global().sync {
S_Log._D_(description: "FTP 로그인 사용자 ID 인증 요청 수행", data: nil)
// MARK: [인풋 데이터 널 체크 수행]
if C_FTP_NWConnection_Client_Module.connection != nil
&& C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_NAME) == true
&& C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_PW) == true {
let commandWithCRLF = "USER \(C_FTP_NWConnection_Client_Module.FTP_USER_NAME)" + "\r\n"
C_FTP_NWConnection_Client_Module.connection?.send(content: commandWithCRLF.data(using: .utf8), completion: .contentProcessed { error in
if let error = error {
C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG = "[Error] : FTP User Auth Error"
S_Log._D_(description: "FTP 로그인 사용자 ID 인증 에러", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG)",
"Description :: \(error)"
])
// [콜백 반환]
completion(false)
return
} else {
S_Log._D_(description: "FTP 로그인 사용자 ID 인증 성공", data: [
"commandWithIdCRLF :: \(commandWithCRLF)"
])
// [콜백 반환]
completion(true)
return
}
})
}
else {
C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG = "[Error] : Input Data Is Null"
S_Log._D_(description: "FTP 로그인 사용자 ID 인증 수행 에러", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG)"
])
// [콜백 반환]
completion(false)
return
}
}
}
// ------------------------------------------------------------
// MARK: - [SEARCH FAST] : observablePwAuth : FTP 사용자 PW 인증 요청 상태 확인
// ------------------------------------------------------------
static var LOGIN_PW_ERROR_LOG = ""
func observablePwAuth(completion: @escaping (Bool)->()) {
/*
// -----------------------------------------
[observablePwAuth 메소드 설명]
// -----------------------------------------
1. FTP 사용자 PW 인증 요청 상태 확인
// -----------------------------------------
2. 호출 방법 :
C_FTP_NWConnection_Client_Module().observablePwAuth(){(sendResult) in
S_Log._F_(description: "FTP 로그인 사용자 PW 인증 수행 확인", data: ["\(sendResult)"])
if sendResult == true {
}
else {
S_Log._F_(description: "FTP 로그인 사용자 PW 인증 수행 에러 메시지", data: ["\(C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG)"])
}
}
// -----------------------------------------
3. 필요 import :
import Network
// -----------------------------------------
*/
// [변수 선언]
C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG = ""
// [로직 처리 수행]
DispatchQueue.global().sync {
S_Log._D_(description: "FTP 로그인 사용자 PW 인증 요청 수행", data: nil)
// MARK: [인풋 데이터 널 체크 수행]
if C_FTP_NWConnection_Client_Module.connection != nil
&& C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_NAME) == true
&& C_Util().stringNotNull(str: C_FTP_NWConnection_Client_Module.FTP_USER_PW) == true {
let commandWithCRLF = "PASS \(C_FTP_NWConnection_Client_Module.FTP_USER_PW)" + "\r\n"
C_FTP_NWConnection_Client_Module.connection?.send(content: commandWithCRLF.data(using: .utf8), completion: .contentProcessed { error in
if let error = error {
C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG = "[Error] : FTP User Pw Error"
S_Log._D_(description: "FTP 로그인 사용자 PW 인증 에러", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG)",
"Description :: \(error)"
])
// [콜백 반환]
completion(false)
return
} else {
S_Log._D_(description: "FTP 로그인 사용자 PW 인증 성공", data: [
"commandWithPwCRLF :: \(commandWithCRLF)"
])
// [콜백 반환]
completion(true)
return
}
})
}
else {
C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG = "[Error] : Input Data Is Null"
S_Log._D_(description: "FTP 로그인 사용자 PW 인증 수행 에러", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG)"
])
// [콜백 반환]
completion(false)
return
}
}
}
// ------------------------------------------------------------
// MARK: - [SEARCH FAST] : loginCallbackReturn : FTP 로그인 콜백 처리 수행
// ------------------------------------------------------------
func loginCallbackReturn(returnValue: Bool) {
/*
// -----------------------------------------
[loginCallbackReturn 메소드 설명]
// -----------------------------------------
1. FTP 로그인 콜백 처리 수행
// -----------------------------------------
2. 호출 방법 :
self.loginCallbackReturn(returnValue: true)
// -----------------------------------------
3. 필요 import :
import Network
// -----------------------------------------
*/
// -----------------------------------------
// MARK: [True , Flase 에 맞게 변수 초기화 및 로직 처리 수행]
// -----------------------------------------
if returnValue == true { // MARK: [성공]
S_Log._D_(description: "loginCallbackReturn :: 로그인 [성공] 콜백 처리 수행", data: nil)
// [변수 값 초기화]
C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG = ""
C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG = ""
// MARK: [작업 큐 값 변경 >> 로그인 성공 처리 수행]
C_FTP_NWConnection_Client_Module.connectFlag = true
C_FTP_NWConnection_Client_Module.connectOperationQueue.isSuspended = false
}
else { // MARK: [실패]
S_Log._D_(description: "loginCallbackReturn :: 로그인 [실패] 콜백 처리 수행", data: nil)
// [변수 값 추가]
C_FTP_NWConnection_Client_Module.LOGIN_USER_ERROR_LOG = "[Error] : Login Fail"
C_FTP_NWConnection_Client_Module.LOGIN_PW_ERROR_LOG = "[Error] : Login Fail"
// MARK: [로그인 실패 처리 수행]
if C_FTP_NWConnection_Client_Module.connection != nil && C_FTP_NWConnection_Client_Module.connectFlag == false {
C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG = "[Login Auth] : FTP Login Fail"
S_Log._D_(description: "FTP 연결 실패", data: [
"M_LOG :: \(C_FTP_NWConnection_Client_Module.FTP_CONNECT_LOG)"
])
// [MQTT 연결 취소]
C_FTP_NWConnection_Client_Module.connection?.cancel()
}
}
}
// --------------------------------------------------------------------------------------
반응형
'IOS' 카테고리의 다른 글
Comments