Swift 2 如何检查端口是否被占用

5

有人能告诉我如何在Swift2中查找端口是否繁忙吗?

因为我正在编写一个具有自己编写的Tcp服务器的Mac应用程序,但有时它无法启动,因为它“无法绑定到端口”。那么,我如何检查端口是否未被使用,以阻止Tcp服务器的启动按钮,直到端口再次空闲?

而且我不想使用新的框架。

谢谢

2个回答

5

主要代码取自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)"
}

无法编译此行代码:if bind(socketFileDescriptor, &bind_addr, socklen_t(sizeof(sockaddr_in))) == -1 { - Tyler Liu
有编译错误,是什么错误?XCode的版本是多少?在7.2(7C68)版本上是可以的。 - dattk

4

更新 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))))
}

编辑: 调用此函数的示例:

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

嗨。这个方法需要传递端口号,但我想在不知道端口号的情况下列出可用端口。你能提供一些方法吗?谢谢。 - famfamfam
非常抱歉没有仔细阅读这个主题,这是针对macOS的,但我只在寻找iOS的解决方案 :(. 你有处理过吗? - famfamfam
将您的代码添加到xCode项目中后出现了错误:https://imgur.com/a/wglCIXx。我不知道它是否适用于IOS... - famfamfam
我尝试从0运行到65000,但只得到了portNum = 0。你能帮我知道为什么我无法获得端口号吗?摄像头rtsp链接是rtsp://admin:admin@192.168.100.177:5544/cam/realmonitor?channel=1&subtype=0&unicast=true&proto=Onvif。 - famfamfam
运行从0到65000,没有中断,我得到了所有消息“'port'可供使用”。 - famfamfam
嗨,我正在使用模拟器检查本地网络中的相机设备,我正在使用https://github.com/mavris/MMLanScan扫描所有可用的IP地址,但无法获取端口,所以我决定使用您的方法来检查端口。这是我的代码,当找到与我的相机IP地址匹配的新IP时:https://imgur.com/a/K0KpN4C,然后这是日志:https://imgur.com/a/Cophigk。 - famfamfam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接