iOS - Network Framework TCP 통신

이한솔·2024년 10월 6일
0

iOS 앱개발 🍏

목록 보기
54/54

TCP 통신

TCP(Transmission Control Protocol) 통신은 데이터 전송을 위한 프로토콜 중 하나로, 신뢰성 있는 연결형 통신을 제공한다.

TCP 통신은 Swift에서는 Network 프레임워크, SwiftSocket, StarScream 라이브러리 등을 사용할 수 있다. Objective-C에서는 NSStream 클래스, CocoaAsyncSocket, GCDAsyncSocket, SocketRocket, CFNetwork 라이브러리 등을 사용해서 처리할 수 있다.

아래 예제는 Swift와 Network 프레임워크를 사용해서 구현했다!



TCP 통신 과정

  1. 서버 생성 및 시작
    TCP 서버를 생성하고 시작한다. 서버는 지정된 포트에서 NWListener를 사용해서 네트워크 연결을 수립하고, 새로운 클라이언트 연결이 감지되면 newConnectionHandler가 호출되어 클라이언트의 연결 요청을 처리한다.
import Network

class TCPServer {
    let listener: NWListener
    let queue = DispatchQueue(label: "TCPServerQueue")
    
    init(port: UInt16) throws {
        let parameters = NWParameters.tcp
        listener = try NWListener(using: parameters, on: NWEndpoint.Port(rawValue: port)!)
    }

    func start() {
        print("서버 시작")
        
        listener.newConnectionHandler = { newConnection in
            print("새로운 클라이언트 연결 감지")
            self.handleConnection(connection: newConnection)
        }
        
        listener.start(queue: queue)
    }

    private func handleConnection(connection: NWConnection) {
        connection.start(queue: queue)
        receive(on: connection)
    }
}
  1. 클라이언트 연결
    서버에 연결할 클라이언트를 생성한다.
    NWConnection을 사용하여 지정된 호스트와 포트에 연결을 시도합니다.
    연결 상태가 변경될 때마다 stateUpdateHandler가 호출된다.
class TCPClient {
    let connection: NWConnection
    let queue = DispatchQueue(label: "TCPClientQueue")
    
    init(host: String, port: UInt16) {
        let endpoint = NWEndpoint.Host(host)
        let port = NWEndpoint.Port(rawValue: port)!
        connection = NWConnection(host: endpoint, port: port, using: .tcp)
    }
    
    func start() {
        connection.stateUpdateHandler = { state in
            switch state {
            case .ready:
                print("서버 연결 완료")
                self.receive()
            case .failed(let error):
                print("서버 연결 실패: \(error)")
            default:
                break
            }
        }
        connection.start(queue: queue)
    }
}
  1. 데이터 송신 및 수신
    클라이언트는 send 메소드를 사용하여 서버에 메시지를 전송한다. 이때 메시지는 UTF-8 인코딩으로 변환되어 전송된다.
    서버는 receive 메소드를 통해 클라이언트로부터 데이터를 수신해서 UTF-8로 디코딩하여 문자열로 변환되고, 이를 클라이언트에게 다시 전송한다.
    클라이언트는 서버로부터 받은 메시지를 처리하기 위해 receive() 메소드를 재귀적으로 호출한다.
// 클라이언트
func send(message: String) {
    let data = message.data(using: .utf8)
    connection.send(content: data, completion: .contentProcessed { error in
        if let error = error {
            print("클라 전송 실패: \(error)")
        } else {
            print("클라 전송 성공: \(message)")
        }
    })
}
// 서버
private func receive(on connection: NWConnection) {
    connection.receive(minimumIncompleteLength: 1, maximumLength: 1024) { [weak self] data, context, isComplete, error in
        if let error = error {
            print("서버측 받기 실패: \(error)")
            connection.cancel()
            return
        }

        if let data = data, let message = String(data: data, encoding: .utf8) {
            print("서버측 받기 성공: \(message)")
            // 응답 전송 (optional)
            self?.send(message, on: connection)
        }

        if isComplete {
            connection.cancel()
        } else {
            self?.receive(on: connection)
        }
    }
}
  1. 연결 종료
    데이터 수신이 완료되면 connection.cancel 메소드를 호출하여 연결을 종료한다.
// 클라이언트
if isComplete {
    self?.connection.cancel()
}
// 서버
if isComplete {
    print("연결 종료")
    connection.cancel()
}

해당 코드는 로컬호스트에서 통신하는 코드이다.
만약 다른 네트워크에 있는 호스트와 통신할 경우 서버는 공인 IP 주소를 사용해 외부 네트워크에서 접근할 수 있어야 한다.
클라이언트는 서버의 공인 IP주소와 포트번호로 연결을 시도하고, 서버는 클라이언트의 연결을 수락한다.
이 과정에서 클라이언트와 서버는 서로의 IP 주소와 포트 번호를 알고 있어야 하며, 이를 기반으로 통신을 진행한다.

0개의 댓글