swift2 Swift 2检查端口是否忙碌

vkc1a9a2  于 2022-11-06  发布在  Swift
关注(0)|答案(2)|浏览(160)

有人能告诉我如何在Swift2中发现端口是否忙碌吗?
因为我写了一个mac应用程序,它有一个自己写的Tcp服务器,但有时它不会启动,因为它“* 无法绑定到端口 *"。那么,我如何才能检查如果端口没有使用,阻止Tcp服务器的启动按钮,直到端口是空闲的,再次?
我不想要一个新的框架。
谢谢

lpwwtiir

lpwwtiir1#

主要代码取自Swifter:https://github.com/glock45/swifter

func checkTcpPortForListen(port: in_port_t) -> (Bool, descr: String){

    let socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0)
    if socketFileDescriptor == -1 {
        return (false, "SocketCreationFailed, \(descriptionOfLastError())")
    }

    var addr = sockaddr_in()
      addr.sin_len = __uint8_t(sizeof(sockaddr_in))
      addr.sin_family = sa_family_t(AF_INET)
      addr.sin_port = Int(OSHostByteOrder()) == OSLittleEndian ? _OSSwapInt16(port) : port
      addr.sin_addr = in_addr(s_addr: inet_addr("0.0.0.0"))
      addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0)
    var bind_addr = sockaddr()
    memcpy(&bind_addr, &addr, Int(sizeof(sockaddr_in)))

    if bind(socketFileDescriptor, &bind_addr, socklen_t(sizeof(sockaddr_in))) == -1 {
        let details = descriptionOfLastError()
        release(socketFileDescriptor)
        return (false, "\(port), BindFailed, \(details)")
    }
    if listen(socketFileDescriptor, SOMAXCONN ) == -1 {
        let details = descriptionOfLastError()
        release(socketFileDescriptor)
        return (false, "\(port), ListenFailed, \(details)")
    }
    release(socketFileDescriptor)
    return (true, "\(port) is free for use") 
}

func release(socket: Int32) {
    Darwin.shutdown(socket, SHUT_RDWR)
    close(socket)
}
func descriptionOfLastError() -> String {
    return String.fromCString(UnsafePointer(strerror(errno))) ?? "Error: \(errno)"
}
q5lcpyga

q5lcpyga2#

更新Swift 4的正确答案:

func checkTcpPortForListen(port: in_port_t) -> (Bool, descr: String) {

    let socketFileDescriptor = socket(AF_INET, SOCK_STREAM, 0)
    if socketFileDescriptor == -1 {
        return (false, "SocketCreationFailed, \(descriptionOfLastError())")
    }

    var addr = sockaddr_in()
    let sizeOfSockkAddr = MemoryLayout<sockaddr_in>.size
    addr.sin_len = __uint8_t(sizeOfSockkAddr)
    addr.sin_family = sa_family_t(AF_INET)
    addr.sin_port = Int(OSHostByteOrder()) == OSLittleEndian ? _OSSwapInt16(port) : port
    addr.sin_addr = in_addr(s_addr: inet_addr("0.0.0.0"))
    addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0)
    var bind_addr = sockaddr()
    memcpy(&bind_addr, &addr, Int(sizeOfSockkAddr))

    if Darwin.bind(socketFileDescriptor, &bind_addr, socklen_t(sizeOfSockkAddr)) == -1 {
        let details = descriptionOfLastError()
        release(socket: socketFileDescriptor)
        return (false, "\(port), BindFailed, \(details)")
    }
    if listen(socketFileDescriptor, SOMAXCONN ) == -1 {
        let details = descriptionOfLastError()
        release(socket: socketFileDescriptor)
        return (false, "\(port), ListenFailed, \(details)")
    }
    release(socket: socketFileDescriptor)
    return (true, "\(port) is free for use")
}

func release(socket: Int32) {
    Darwin.shutdown(socket, SHUT_RDWR)
    close(socket)
}

func descriptionOfLastError() -> String {
    return String.init(cString: (UnsafePointer(strerror(errno))))
}

EDIT:调用此函数的示例:

var portNum: UInt16 = 0
        for i in 50000..<65000 {
            let (isFree, _) = checkTcpPortForListen(port: UInt16(i))
            if isFree == true {
                portNum = UInt16(i)
                break;
            }
        }

相关问题