Swift多播多个连接到相同的端口

huangapple go评论103阅读模式
英文:

Swift multicast multiple connection to the same port

问题

我有两个安装在同一设备上的应用程序,它们尝试连接到一个多播组,第一个应用程序成功连接,而第二个应用程序出现错误:
监听器失败,错误为
组进入状态失败(POSIXErrorCode(rawValue: 48): 地址已被使用)

我以为allowLocalEndpointReuse允许多个客户端连接到相同的端口,但它不起作用。

  1. let port = NWEndpoint.Port(portUdp) ?? NWEndpoint.Port(5353)
  2. let host = NWEndpoint.Host(urlUdp)
  3. guard let multicast = try? NWMulticastGroup(for:
  4. [ .hostPort(host: host, port: port) ])
  5. else {
  6. stateMultiCast = "带有URL和端口的错误"
  7. return
  8. }
  9. let parameters = NWParameters.udp
  10. parameters.allowLocalEndpointReuse = true
  11. parameters.allowLocalEndpointReuse
  12. let group = NWConnectionGroup(with: multicast, using: parameters)
  13. group.setReceiveHandler(maximumMessageSize: 16384, rejectOversizedMessages: true)
  14. { (message, content, isComplete) in
  15. // ....
  16. }
  17. group.stateUpdateHandler = { (newState) in
  18. print("组进入状态 \(String(describing: newState))")
  19. }
  20. 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.

  1. let port = NWEndpoint.Port(portUdp) ?? NWEndpoint.Port(5353)
  2. let host = NWEndpoint.Host(urlUdp)
  3. guard let multicast = try? NWMulticastGroup(for:
  4. [ .hostPort(host: host, port: port) ])
  5. else {
  6. stateMultiCast = "Error with url and port"
  7. return
  8. }
  9. let parameters = NWParameters.udp
  10. parameters.allowLocalEndpointReuse = true
  11. parameters.allowLocalEndpointReuse
  12. let group = NWConnectionGroup(with: multicast, using: parameters)
  13. group.setReceiveHandler(maximumMessageSize: 16384, rejectOversizedMessages: true)
  14. { (message, content, isComplete) in
  15. ....
  16. }
  17. group.stateUpdateHandler = { (newState) in
  18. print("Group entered state \(String(describing: newState))")
  19. }
  20. 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

我找到了一个不同于苹果推荐的多播组的解决方案:

  1. func setupMulticastSocket(urlUdp: String, portUdp: String) -> Int32 {
  2. let multicastAddress = urlUdp
  3. let multicastPort: UInt16 = UInt16(portUdp) ?? 0
  4. // 创建一个UDP套接字
  5. let socketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0)
  6. guard socketFileDescriptor != -1 else {
  7. print("创建套接字失败")
  8. exit(1)
  9. }
  10. // 启用多播回环
  11. var loop: UInt32 = 1
  12. guard setsockopt(socketFileDescriptor, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, socklen_t(MemoryLayout<UInt32>.size)) != -1 else {
  13. print("启用多播回环失败")
  14. exit(1)
  15. }
  16. var reuseFlag: Int32 = 1
  17. let reuseOption = withUnsafePointer(to: &reuseFlag) { ptr in
  18. return UnsafeRawPointer(ptr).assumingMemoryBound(to: Int32.self)
  19. }
  20. if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEPORT, reuseOption, socklen_t(MemoryLayout<Int32>.size)) == -1 {
  21. print("设置SO_REUSEPORT出错: \(String(describing: strerror(errno)))")
  22. return -1
  23. }
  24. if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, reuseOption, socklen_t(MemoryLayout<Int32>.size)) == -1 {
  25. print("设置SO_REUSEADDR出错: \(String(describing: strerror(errno)))")
  26. return -1
  27. }
  28. // 将套接字绑定到特定的地址和端口
  29. var socketAddress = sockaddr_in()
  30. socketAddress.sin_len = __uint8_t(MemoryLayout<sockaddr_in>.size)
  31. socketAddress.sin_family = sa_family_t(AF_INET)
  32. socketAddress.sin_port = multicastPort.bigEndian
  33. socketAddress.sin_addr.s_addr = CFSwapInt32HostToBig(INADDR_ANY)
  34. withUnsafePointer(to: &socketAddress) { pointer in
  35. let bindResult = pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { addrPointer in
  36. bind(socketFileDescriptor, addrPointer, socklen_t(MemoryLayout<sockaddr_in>.size))
  37. }
  38. guard bindResult != -1 else {
  39. print("绑定套接字失败")
  40. exit(1)
  41. }
  42. }
  43. // 加入多播组
  44. var multicastRequest = ip_mreq()
  45. multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastAddress)
  46. multicastRequest.imr_interface.s_addr = CFSwapInt32HostToBig(INADDR_ANY)
  47. guard setsockopt(socketFileDescriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP, &multicastRequest, socklen_t(MemoryLayout<ip_mreq>.size)) != -1 else {
  48. print("加入多播组失败")
  49. exit(1)
  50. }
  51. return socketFileDescriptor
  52. }
  53. // 调用函数如下:
  54. let socketFD = setupMulticastSocket(urlUdp: urlUdp, portUdp: portUdp)
  55. if socketFD != -1 {
  56. print("多播套接字设置成功。")
  57. } else {
  58. print("设置多播套接字失败。")
  59. }
  60. let bufferSize = 1024
  61. var buffer = [UInt8](repeating: 0, count: bufferSize)
  62. // 读取接收到的消息
  63. while true {
  64. let bytesRead = recv(socketFD, &buffer, buffer.count, 0)
  65. if bytesRead > 0 {
  66. let messageData = Data(bytes: buffer, count: bytesRead)
  67. let hexString = messageData.reduce("") { $0 + String(format: "%02x", $1) }
  68. let decodedData = Data(hexString: hexString)!
  69. if let decodedData = Data(hexString: hexString){
  70. newDataRsaReceived(decodedData ?? Data())
  71. }
  72. }
  73. }

使用这个解决方案,多个客户端(应用程序)可以连接到相同的端口。

英文:

I found a solution different of multicast group that apple recommand :

func setupMulticastSocket(urlUdp : String, portUdp : String) -> Int32 {

  1. let multicastAddress = urlUdp
  2. let multicastPort: UInt16 = UInt16(portUdp) ?? 0
  3. // Create a UDP socket
  4. let socketFileDescriptor = socket(AF_INET, SOCK_DGRAM, 0)
  5. guard socketFileDescriptor != -1 else {
  6. print(&quot;Failed to create socket&quot;)
  7. exit(1)
  8. }
  9. // Enable multicast loopback
  10. var loop: UInt32 = 1
  11. guard setsockopt(socketFileDescriptor, IPPROTO_IP, IP_MULTICAST_LOOP, &amp;loop, socklen_t(MemoryLayout&lt;UInt32&gt;.size)) != -1 else {
  12. print(&quot;Failed to enable multicast loopback&quot;)
  13. exit(1)
  14. }
  15. var reuseFlag: Int32 = 1
  16. let reuseOption = withUnsafePointer(to: &amp;reuseFlag) { ptr in
  17. return UnsafeRawPointer(ptr).assumingMemoryBound(to: Int32.self)
  18. }
  19. if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEPORT, reuseOption, socklen_t(MemoryLayout&lt;Int32&gt;.size)) == -1 {
  20. print(&quot;Error setting SO_REUSEPORT: \(String(describing: strerror(errno)))&quot;)
  21. return -1
  22. }
  23. if setsockopt(socketFileDescriptor, SOL_SOCKET, SO_REUSEADDR, reuseOption, socklen_t(MemoryLayout&lt;Int32&gt;.size)) == -1 {
  24. print(&quot;Error setting SO_REUSEADDR: \(String(describing: strerror(errno)))&quot;)
  25. return -1
  26. }
  27. // Bind the socket to a specific address and port
  28. var socketAddress = sockaddr_in()
  29. socketAddress.sin_len = __uint8_t(MemoryLayout&lt;sockaddr_in&gt;.size)
  30. socketAddress.sin_family = sa_family_t(AF_INET)
  31. socketAddress.sin_port = multicastPort.bigEndian
  32. socketAddress.sin_addr.s_addr = CFSwapInt32HostToBig(INADDR_ANY)
  33. withUnsafePointer(to: &amp;socketAddress) { pointer in
  34. let bindResult = pointer.withMemoryRebound(to: sockaddr.self, capacity: 1) { addrPointer in
  35. bind(socketFileDescriptor, addrPointer, socklen_t(MemoryLayout&lt;sockaddr_in&gt;.size))
  36. }
  37. guard bindResult != -1 else {
  38. print(&quot;Failed to bind socket&quot;)
  39. exit(1)
  40. }
  41. }
  42. // Join the multicast group
  43. var multicastRequest = ip_mreq()
  44. multicastRequest.imr_multiaddr.s_addr = inet_addr(multicastAddress)
  45. multicastRequest.imr_interface.s_addr = CFSwapInt32HostToBig(INADDR_ANY)
  46. guard setsockopt(socketFileDescriptor, IPPROTO_IP, IP_ADD_MEMBERSHIP, &amp;multicastRequest, socklen_t(MemoryLayout&lt;ip_mreq&gt;.size)) != -1 else {
  47. print(&quot;Failed to join multicast group&quot;)
  48. exit(1)
  49. }
  50. return socketFileDescriptor
  51. }

I call the function like that :

  1. let socketFD = setupMulticastSocket(urlUdp: urlUdp, portUdp: portUdp)
  2. if socketFD != -1 {
  3. print(&quot;Multicast socket set up successfully.&quot;)
  4. } else {
  5. print(&quot;Failed to set up multicast socket.&quot;)
  6. }
  7. let bufferSize = 1024
  8. var buffer = [UInt8](repeating: 0, count: bufferSize)
  9. // Reading message received
  10. while true {
  11. let bytesRead = recv(socketFD, &amp;buffer, buffer.count, 0)
  12. if bytesRead &gt; 0 {
  13. let messageData = Data(bytes: buffer, count: bytesRead)
  14. let hexString = messageData.reduce(&quot;&quot;) { $0 + String(format: &quot;%02x&quot;, $1) }
  15. let decodedData = Data(hexString: hexString)!
  16. if let decodedData = Data(hexString: hexString){
  17. newDataRsaReceived(decodedData ?? Data())
  18. }
  19. }
  20. }

With this solution multiple client (application) can connect to the same port

huangapple
  • 本文由 发表于 2023年6月12日 21:59:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76457403.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定