英文:
Swift multicast multiple connection to the same port
问题
我有两个安装在同一设备上的应用程序,它们尝试连接到一个多播组,第一个应用程序成功连接,而第二个应用程序出现错误:
监听器失败,错误为
组进入状态失败(POSIXErrorCode(rawValue: 48): 地址已被使用)
我以为allowLocalEndpointReuse允许多个客户端连接到相同的端口,但它不起作用。
let port = NWEndpoint.Port(portUdp) ?? NWEndpoint.Port(5353)
let host = NWEndpoint.Host(urlUdp)
guard let multicast = try? NWMulticastGroup(for:
[ .hostPort(host: host, port: port) ])
else {
stateMultiCast = "带有URL和端口的错误"
return
}
let parameters = NWParameters.udp
parameters.allowLocalEndpointReuse = true
parameters.allowLocalEndpointReuse
let group = NWConnectionGroup(with: multicast, using: parameters)
group.setReceiveHandler(maximumMessageSize: 16384, rejectOversizedMessages: true)
{ (message, content, isComplete) in
// ....
}
group.stateUpdateHandler = { (newState) in
print("组进入状态 \(String(describing: newState))")
}
group.start(queue: .main)
如何让多个应用程序使用相同的端口,以便这些应用程序可以接收UDP服务器发送的所有相同消息?
感谢您的帮助。
英文:
I have two applications installed on the same device and they trying to connect to a multicast group the first application has a succeed connection the second one has error :
listener failed with error
Group entered state failed(POSIXErrorCode(rawValue: 48): Address already in use)
I thought that allowLocalEndpointReuse allows several clients to connect to the same port
but it doesn't work.
let port = NWEndpoint.Port(portUdp) ?? NWEndpoint.Port(5353)
let host = NWEndpoint.Host(urlUdp)
guard let multicast = try? NWMulticastGroup(for:
[ .hostPort(host: host, port: port) ])
else {
stateMultiCast = "Error with url and port"
return
}
let parameters = NWParameters.udp
parameters.allowLocalEndpointReuse = true
parameters.allowLocalEndpointReuse
let group = NWConnectionGroup(with: multicast, using: parameters)
group.setReceiveHandler(maximumMessageSize: 16384, rejectOversizedMessages: true)
{ (message, content, isComplete) in
....
}
group.stateUpdateHandler = { (newState) in
print("Group entered state \(String(describing: newState))")
}
group.start(queue: .main)
How can i use the same port for several application so this application can receive all the same message sent by udp server ?
Thank you for your help
答案1
得分: -1
我找到了一个不同于苹果推荐的多播组的解决方案:
func setupMulticastSocket(urlUdp: String, portUdp: String) -> Int32 {
let multicastAddress = urlUdp
let multicastPort: UInt16 = UInt16(portUdp) ?? 0
// 创建一个UDP套接字
let socketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0)
guard socketFileDescriptor != -1 else {
print("创建套接字失败")
exit(1)
}
// 启用多播回环
var loop: UInt32 = 1
guard setsockopt(socketFileDescriptor, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, socklen_t(MemoryLayout<UInt32>.size)) != -1 else {
print("启用多播回环失败")
exit(1)
}
var reuseFlag: Int32 = 1
let reuseOption = withUnsafePointer(to: &reuseFlag) { ptr in
return UnsafeRawPointer(ptr).assumingMemoryBound(to: Int32.self)
}
if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEPORT, reuseOption, socklen_t(MemoryLayout<Int32>.size)) == -1 {
print("设置SO_REUSEPORT出错: \(String(describing: strerror(errno)))")
return -1
}
if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, reuseOption, socklen_t(MemoryLayout<Int32>.size)) == -1 {
print("设置SO_REUSEADDR出错: \(String(describing: strerror(errno)))")
return -1
}
// 将套接字绑定到特定的地址和端口
var socketAddress = sockaddr_in()
socketAddress.sin_len = __uint8_t(MemoryLayout<sockaddr_in>.size)
socketAddress.sin_family = sa_family_t(AF_INET)
socketAddress.sin_port = multicastPort.bigEndian
socketAddress.sin_addr.s_addr = CFSwapInt32HostToBig(INADDR_ANY)
withUnsafePointer(to: &socketAddress) { pointer in
let bindResult = pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { addrPointer in
bind(socketFileDescriptor, addrPointer, socklen_t(MemoryLayout<sockaddr_in>.size))
}
guard bindResult != -1 else {
print("绑定套接字失败")
exit(1)
}
}
// 加入多播组
var multicastRequest = ip_mreq()
multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastAddress)
multicastRequest.imr_interface.s_addr = CFSwapInt32HostToBig(INADDR_ANY)
guard setsockopt(socketFileDescriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicastRequest, socklen_t(MemoryLayout<ip_mreq>.size)) != -1 else {
print("加入多播组失败")
exit(1)
}
return socketFileDescriptor
}
// 调用函数如下:
let socketFD = setupMulticastSocket(urlUdp: urlUdp, portUdp: portUdp)
if socketFD != -1 {
print("多播套接字设置成功。")
} else {
print("设置多播套接字失败。")
}
let bufferSize = 1024
var buffer = [UInt8](repeating: 0, count: bufferSize)
// 读取接收到的消息
while true {
let bytesRead = recv(socketFD, &buffer, buffer.count, 0)
if bytesRead > 0 {
let messageData = Data(bytes: buffer, count: bytesRead)
let hexString = messageData.reduce("") { $0 + String(format: "%02x", $1) }
let decodedData = Data(hexString: hexString)!
if let decodedData = Data(hexString: hexString){
newDataRsaReceived(decodedData ?? Data())
}
}
}
使用这个解决方案,多个客户端(应用程序)可以连接到相同的端口。
英文:
I found a solution different of multicast group that apple recommand :
func setupMulticastSocket(urlUdp : String, portUdp : String) -> Int32 {
let multicastAddress = urlUdp
let multicastPort: UInt16 = UInt16(portUdp) ?? 0
// Create a UDP socket
let socketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0)
guard socketFileDescriptor != -1 else {
print("Failed to create socket")
exit(1)
}
// Enable multicast loopback
var loop: UInt32 = 1
guard setsockopt(socketFileDescriptor, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, socklen_t(MemoryLayout<UInt32>.size)) != -1 else {
print("Failed to enable multicast loopback")
exit(1)
}
var reuseFlag: Int32 = 1
let reuseOption = withUnsafePointer(to: &reuseFlag) { ptr in
return UnsafeRawPointer(ptr).assumingMemoryBound(to: Int32.self)
}
if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEPORT, reuseOption, socklen_t(MemoryLayout<Int32>.size)) == -1 {
print("Error setting SO_REUSEPORT: \(String(describing: strerror(errno)))")
return -1
}
if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, reuseOption, socklen_t(MemoryLayout<Int32>.size)) == -1 {
print("Error setting SO_REUSEADDR: \(String(describing: strerror(errno)))")
return -1
}
// Bind the socket to a specific address and port
var socketAddress = sockaddr_in()
socketAddress.sin_len = __uint8_t(MemoryLayout<sockaddr_in>.size)
socketAddress.sin_family = sa_family_t(AF_INET)
socketAddress.sin_port = multicastPort.bigEndian
socketAddress.sin_addr.s_addr = CFSwapInt32HostToBig(INADDR_ANY)
withUnsafePointer(to: &socketAddress) { pointer in
let bindResult = pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { addrPointer in
bind(socketFileDescriptor, addrPointer, socklen_t(MemoryLayout<sockaddr_in>.size))
}
guard bindResult != -1 else {
print("Failed to bind socket")
exit(1)
}
}
// Join the multicast group
var multicastRequest = ip_mreq()
multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastAddress)
multicastRequest.imr_interface.s_addr = CFSwapInt32HostToBig(INADDR_ANY)
guard setsockopt(socketFileDescriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicastRequest, socklen_t(MemoryLayout<ip_mreq>.size)) != -1 else {
print("Failed to join multicast group")
exit(1)
}
return socketFileDescriptor
}
I call the function like that :
let socketFD = setupMulticastSocket(urlUdp: urlUdp, portUdp: portUdp)
if socketFD != -1 {
print("Multicast socket set up successfully.")
} else {
print("Failed to set up multicast socket.")
}
let bufferSize = 1024
var buffer = [UInt8](repeating: 0, count: bufferSize)
// Reading message received
while true {
let bytesRead = recv(socketFD, &buffer, buffer.count, 0)
if bytesRead > 0 {
let messageData = Data(bytes: buffer, count: bytesRead)
let hexString = messageData.reduce("") { $0 + String(format: "%02x", $1) }
let decodedData = Data(hexString: hexString)!
if let decodedData = Data(hexString: hexString){
newDataRsaReceived(decodedData ?? Data())
}
}
}
With this solution multiple client (application) can connect to the same port
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论