有人能告诉我如何在Swift2中查找端口是否繁忙吗?
因为我正在编写一个具有自己编写的Tcp服务器的Mac应用程序,但有时它无法启动,因为它“无法绑定到端口”。那么,我如何检查端口是否未被使用,以阻止Tcp服务器的启动按钮,直到端口再次空闲?
而且我不想使用新的框架。
谢谢
有人能告诉我如何在Swift2中查找端口是否繁忙吗?
因为我正在编写一个具有自己编写的Tcp服务器的Mac应用程序,但有时它无法启动,因为它“无法绑定到端口”。那么,我如何检查端口是否未被使用,以阻止Tcp服务器的启动按钮,直到端口再次空闲?
而且我不想使用新的框架。
谢谢
主要代码取自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)"
}
更新 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;
}
}
if bind(socketFileDescriptor, &bind_addr, socklen_t(sizeof(sockaddr_in))) == -1 {
- Tyler Liu