본문 바로가기

iOS

iOS UDP 통신 쉬운 예제 코드

728x90
반응형
SMALL

예제 코드

*설정 앱 -> Wi-Fi -> IP 주소에서 IP주소를 찾고 밑의 코드에 "기기의 IPAddress"부분을 수정해주세요.

import UIKit

class ViewController: UIViewController {
    let ipAddress = "기기의 IPAddress" // 메시지를 전송할 IP 주소를 저장한다.
    let port: UInt16 = 12345 // 메시지를 전송할 포트 번호를 저장한다.
    let receivedMessageLabel = UILabel() //수신된 메시지를 출력할 UILabel 객체를 생성한다.
    var count:Int = 0 // 수신된 메시지의 수를 저장할 변수를 선언한다.

    //UDP 메시지를 전송하는 함수를 선언한다.
    func sendUDPMessage(message: String, ipAddress: String, port: UInt16) {
        // sockaddr_in 객체를 생성하고 서버의 IP 주소와 포트 번호를 설정한다.
        var serverAddress = sockaddr_in( //  sockaddr_in 구조체는 IPv4 주소를 나타내며, 이를 초기화하는 코드입니다.
            sin_len: __uint8_t(MemoryLayout<sockaddr_in>.size), // sin_len은 구조체의 크기를 의미하며, MemoryLayout<sockaddr_in>.size로 해당 구조체의 크기를 지정합니다.
            sin_family: sa_family_t(AF_INET), // sin_family는 주소 체계를 지정하는데, AF_INET으로 IPv4를 사용하겠다는 것을 나타냅니다.
            sin_port: in_port_t(port).bigEndian, // sin_port는 포트 번호를 나타내며, in_port_t(port).bigEndian으로 입력받은 포트 번호를 빅 엔디안 형식으로 지정합니다.
            sin_addr: in_addr(s_addr: inet_addr(ipAddress)), // sin_addr은 IP 주소를 나타내며, INADDR_ANY를 사용하여 모든 IP 주소에서 수신할 수 있도록 합니다.
            sin_zero: (0, 0, 0, 0, 0, 0, 0, 0) // sin_zero는 구조체의 나머지 부분을 모두 0으로 초기화합니다.
        )
        // 클라이언트 소켓을 생성한다.
        var clientSocket = socket(AF_INET, SOCK_DGRAM, 0)
        
        // 메시지를 C 스타일 문자열로 변환하고, sendto() 함수로 UDP 메시지를 전송한다.
        let sent = message.withCString {
            sendto(
                clientSocket,
                $0,
                Int(strlen($0)),
                0,
                sockaddr_cast(&serverAddress),
                socklen_t(MemoryLayout<sockaddr_in>.size)
            )
        }
        
        // 메시지 전송에 실패한 경우 에러 메시지를 출력한다.
        if sent < 0 {
            print("Error sending message: (sent)")
        }
        
        // 클라이언트 소켓을 닫는다.
        close(clientSocket)
    }
    
    // sockaddr_cast 함수를 정의한다.
    func sockaddr_cast(_ p: UnsafeMutableRawPointer) -> UnsafeMutablePointer<sockaddr> {
        return p.assumingMemoryBound(to: sockaddr.self)
    }

    // UDP 메시지를 수신하는 함수를 정의한다.
    func receiveUDPMessage(port: UInt16) {

        // sockaddr_in 객체를 생성하고 수신할 포트 번호를 설정한다.
        var serverAddress = sockaddr_in(
            sin_len: __uint8_t(MemoryLayout<sockaddr_in>.size),
            sin_family: sa_family_t(AF_INET),
            sin_port: in_port_t(port).bigEndian,
            sin_addr: in_addr(s_addr: INADDR_ANY),
            sin_zero: (0, 0, 0, 0, 0, 0, 0, 0)
        )
        
        // 서버 소켓을 생성한다.
        var serverSocket = socket(AF_INET, SOCK_DGRAM, 0)
        
        // bind() 함수를 호출하여 소켓을 주소와 연결한다.
        var status = bind(
            serverSocket,
            sockaddr_cast(&serverAddress),
            socklen_t(MemoryLayout<sockaddr_in>.size)
        )
        
        // 소켓 연결에 실패한 경우 에러 메시지를 출력한다.
        if status != 0 {
            print("Error binding socket")
            return
        }
        
        // 클라이언트 주소 정보를 저장할 sockaddr_in 객체를 생성한다.
        var clientAddress = sockaddr_in()
        
        // 클라이언트 주소 정보의 길이를 저장한다.
        var clientAddressLength = socklen_t(MemoryLayout<sockaddr_in>.size)
        
        // 수신된 메시지를 저장할 버퍼를 생성한다.
        var buffer = [CChar](repeating: 0, count: 1024)
        
        // 무한 루프를 돌면서 메시지를 수신하고 출력한다.
        while true {
            
            // recvfrom() 함수를 호출하여 UDP 메시지를 수신한다.
                let bytesRead = recvfrom(
                    serverSocket,
                    &buffer,
                    buffer.count,
                    0,
                    sockaddr_cast(&clientAddress),
                    &clientAddressLength
                )
            
            // 수신된 메시지를 String 객체로 변환한다.
                let message = String(cString: buffer)
                DispatchQueue.main.async { // UI 업데이트는 메인 스레드에서 실행되어야 함
                    self.count += 1
                    self.receivedMessageLabel.text = "Received message: \(message) \(self.count)"
                }
            }
    }

    // 버튼이 눌릴 때 호출되는 함수
    @objc func buttonPressed(sender: UIButton) {
        sendUDPMessage(message: "Hello, UDP!", ipAddress: ipAddress, port: port)
    }

    // 예제를 위한 메시지 전송
    override func viewDidLoad() {
        super.viewDidLoad()
        let button = UIButton(type: .system)
        button.setTitle("Send Message", for: .normal)
        button.addTarget(self, action: #selector(buttonPressed(sender:)), for: .touchUpInside)
        view.addSubview(button)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        button.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        
        receivedMessageLabel.text = "UDP?"
        receivedMessageLabel.textColor = .red
        
        
        // 라벨 설정
         receivedMessageLabel.textAlignment = .center
         receivedMessageLabel.font = UIFont.systemFont(ofSize: 20)
         receivedMessageLabel.numberOfLines = 0
         view.addSubview(receivedMessageLabel)
         
         // 라벨 위치 설정
         receivedMessageLabel.translatesAutoresizingMaskIntoConstraints = false
         receivedMessageLabel.topAnchor.constraint(equalTo: view.topAnchor, constant: 50).isActive = true
         receivedMessageLabel.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 20).isActive = true
         receivedMessageLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20).isActive = true
        
        // 비동기적으로 함수 실행
        DispatchQueue.global(qos: .background).async {
            self.receiveUDPMessage(port: self.port)
        }
    }
}

 

시뮬레이터에서 버튼 터치 시 아이폰에서 Received message: \(message) \(self.count) 메세지를 확인 가능합니다. :)

 

 

 

 

728x90
반응형
LIST

'iOS' 카테고리의 다른 글

객체지향의 역할, 책임 차이 쉬운 예  (0) 2023.05.03
솔리드(SOLID) 원칙  (0) 2023.05.03
TCP, UDP  (0) 2023.04.29
강한순환참조  (0) 2023.04.28
AppDelegate  (0) 2023.04.27