You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

FreePortManager.cs 2.1 kB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. // Copyright (c) Microsoft Corporation. All rights reserved.
  2. // FreePortManager.cs
  3. using System.Diagnostics;
  4. namespace Microsoft.AutoGen.Core.Grpc.Tests;
  5. internal sealed class FreePortManager
  6. {
  7. private HashSet<int> takenPorts = new();
  8. private readonly object mutex = new();
  9. [DebuggerDisplay($"{{{nameof(Port)}}}")]
  10. internal sealed class PortTicket(FreePortManager portManager, int port) : IDisposable
  11. {
  12. private FreePortManager? portManager = portManager;
  13. public int Port { get; } = port;
  14. public void Dispose()
  15. {
  16. FreePortManager? localPortManager = Interlocked.Exchange(ref this.portManager, null);
  17. localPortManager?.takenPorts.Remove(this.Port);
  18. }
  19. public override string ToString()
  20. {
  21. return this.Port.ToString();
  22. }
  23. public override bool Equals(object? obj)
  24. {
  25. return obj is PortTicket ticket && ticket.Port == this.Port;
  26. }
  27. public override int GetHashCode()
  28. {
  29. return this.Port.GetHashCode();
  30. }
  31. public static implicit operator int(PortTicket ticket) => ticket.Port;
  32. public static implicit operator string(PortTicket ticket) => ticket.ToString();
  33. }
  34. public PortTicket GetAvailablePort()
  35. {
  36. lock (mutex)
  37. {
  38. int port;
  39. do
  40. {
  41. using var listener = new System.Net.Sockets.TcpListener(System.Net.IPAddress.Loopback, 0);
  42. listener.Start();
  43. port = ((System.Net.IPEndPoint)listener.LocalEndpoint).Port;
  44. listener.Stop();
  45. listener.Dispose();
  46. Thread.Yield(); // Let the listener actually shut down before we try to use the port
  47. } while (takenPorts.Contains(port));
  48. takenPorts.Add(port);
  49. Console.WriteLine($"FreePortManager: Yielding port {port}");
  50. Debug.WriteLine($"FreePortManager: Yielding port {port}");
  51. return new PortTicket(this, port);
  52. }
  53. }
  54. }