如何在 Swift 中从 sockaddr_in 获取 sockaddr?

Posted

技术标签:

【中文标题】如何在 Swift 中从 sockaddr_in 获取 sockaddr?【英文标题】:How to get sockaddr from sockaddr_in in Swift? 【发布时间】:2021-12-12 07:31:43 【问题描述】:

您好,这是我成功发送广播消息的目标代码,

- (void)send: (NSString *)address
    
        int socketSD = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
        if (socketSD <= 0) 
            NSLog(@"Error: Could not open socket.");
            return;
        
        
        // set socket options enable broadcast
        int broadcastEnable = 1;
        int ret = setsockopt(socketSD, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, sizeof(broadcastEnable));
        if (ret) 
            NSLog(@"Error: Could not open set socket to broadcast mode");
            close(socketSD);
            return;
        
        
        // Configure the port and ip we want to send to
        struct sockaddr_in broadcastAddr;
        memset(&broadcastAddr, 0, sizeof(broadcastAddr));
        broadcastAddr.sin_family = AF_INET;
        
        const char *broadCast = [address UTF8String];
        
        inet_pton(AF_INET, broadCast, &broadcastAddr.sin_addr);
        
        broadcastAddr.sin_port = htons(2425);
        
        char *request = "message";
        ret = sendto(socketSD, request, strlen(request), 0, (struct sockaddr*)&broadcastAddr, sizeof(broadcastAddr));
       
        if (ret < 0) 
            NSLog(@"Error: Could not open send broadcast.");
            close(socketSD);
            return;
         
        
        close(socketSD); 
    

我尝试将此代码转换为 swift,但我不知道如何将 sockaddr_in 转换为 sockaddr。这是我尝试过的快速代码,

func send(_ address: String) 
        let socketSD = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)
        if socketSD <= 0 
            print("Error: Could not open socket.")
            return
        

        // set socket options enable broadcast
        var broadcastEnable = 1
       
        var ret = setsockopt(socketSD, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, socklen_t(MemoryLayout.size(ofValue: broadcastEnable)))
        
        if ret != 0 
            print("Error: Could not open set socket to broadcast mode")
            close(socketSD)
            return
        
        
        var broadcastAddr: sockaddr_in!
        
        memset(&broadcastAddr, 0, MemoryLayout.size(ofValue: broadcastAddr))
        
        if broadcastAddr == nil
            
            return
        
        
        broadcastAddr.sin_family = sa_family_t(AF_INET)

        let broadCast: UnsafeMutablePointer<Int8>? = address.toUnsafeMutablePointer()

        inet_pton(AF_INET, broadCast, &broadcastAddr.sin_addr)

        broadcastAddr.sin_port = in_port_t(2425)
    
        let request = ("message" as NSString).utf8String
         
        
        var unsafePointerAddress: sockaddr = // I am not sure  how to get sockaddr from `broadcastAddr` 
        
        ret =  Int32(
            
            sendto(socketSD, request!, strlen(request!), 0, &unsafePointerAddress, socklen_t(MemoryLayout.size(ofValue: broadcastAddr)))
        )

        if ret < 0 
            print("Error: Could not open send broadcast.")
            close(socketSD)
            return
        

        close(socketSD)
    

请帮助我。谢谢。

【问题讨论】:

【参考方案1】:

我根据您的开头将代码翻译为:

func send(_ address: String) 
    let socketSD = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)
    guard socketSD > 0 else  print("Error: Could not open socket."); return 
    defer  close(socketSD) 

    // set socket options enable broadcast
    var broadcastEnable = 1
    let ret = setsockopt(socketSD, SOL_SOCKET, SO_BROADCAST, &broadcastEnable, socklen_t(MemoryLayout.size(ofValue: broadcastEnable)))
    guard ret == 0 else  print("Error: Could not open set socket to broadcast mode"); return 

    var broadcastAddr = sockaddr_in(sin_len: 0,
                                    sin_family: sa_family_t(AF_INET),
                                    sin_port: in_port_t(UInt16(1314).bigEndian),
                                    sin_addr: in_addr(s_addr: 0),
                                    sin_zero: (0,0,0,0,0,0,0,0))
    let broadcastAddrSize = MemoryLayout.size(ofValue: broadcastAddr)

    address.withCString 
        address in
        inet_pton(AF_INET, address, &broadcastAddr.sin_addr)
    

    let result = withUnsafePointer(to: &broadcastAddr) 
        return $0.withMemoryRebound(to: sockaddr.self, capacity: 1)  aSockaddr in
            return "message".withCString  message in
                return sendto(socketSD, message, strlen(message), 0, aSockaddr, socklen_t(broadcastAddrSize))

            
        
    

    print(result)
    if result < 0 
        print("Error: Could not open send broadcast. \(result)")
    

如果我运行它,它不会崩溃并返回肯定的结果,但我不知道它是否正常工作。

【讨论】:

感谢您的回答。但它不起作用。我收到错误Could not open send broadcast. -1nc -luk 1314 是收听广播消息的终端命令。使用ifconfig可以得到broadcast的IP地址。 Swift 版本 Objective-C 版本都给了我相同的结果 对 sendto 的调用失败并返回 -1 并留下 errno 值为 1 (域错误)。你知道 Objective-C 的愿景是否奏效了吗? 是的,您的解决方案运行良好。问题是我们忘记检查Xcode中App Sandbox的传出连接Signing and Capabilities.谢谢你的回答。

以上是关于如何在 Swift 中从 sockaddr_in 获取 sockaddr?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中从 Firebase 接收数组

如何在 Swift 中从 CloudKit 中删除资产?

如何在 Swift 中从数组中删除一个元素

如何在 Swift 中从 NSDictionary 生成 JSON 数据

如何在 Swift 中从 alamofire 中提取数据? [复制]

如何在 Swift 中从 Facebook 获取用户名