1
1
"""Session manager for gRPC."""
2
+
2
3
from contextlib import contextmanager
3
4
from enum import Enum
5
+ import errno
4
6
from shutil import which
7
+ import socket
5
8
from struct import pack , unpack
6
9
import subprocess
7
10
from sys import modules
142
145
from ansys .edb .core .inner .exceptions import EDBSessionException , ErrorCode
143
146
from ansys .edb .core .inner .interceptors import ExceptionInterceptor , LoggingInterceptor
144
147
148
+ DEFAULT_ADDRESS = "localhost"
149
+
145
150
# The session module singleton
146
151
MOD = modules [__name__ ]
147
152
MOD .current_session = None
@@ -172,8 +177,8 @@ def __init__(self, ip_address, port_num, ansys_em_root):
172
177
if MOD .current_session is not None :
173
178
raise EDBSessionException (ErrorCode .STARTUP_MULTI_SESSIONS )
174
179
175
- self .ip_address = ip_address or "localhost"
176
- self .port_num = port_num
180
+ self .ip_address = ip_address or DEFAULT_ADDRESS
181
+ self .port_num = port_num or _find_available_port ()
177
182
self .ansys_em_root = ansys_em_root
178
183
self .channel = None
179
184
self .local_server_proc = None
@@ -457,8 +462,8 @@ def launch_session(ansys_em_root, port_num=None):
457
462
ansys_em_root : str
458
463
Directory where the ``EDB_RPC_Server.exe`` file is installed.
459
464
port_num : int, default: None
460
- Port number to listen on. The default is ``None``, in which
461
- case localhost is used .
465
+ Port number to listen on. The default is ``None``, in which case a port in [50051, 60000]
466
+ is selected .
462
467
463
468
Examples
464
469
--------
@@ -480,15 +485,16 @@ def launch_session(ansys_em_root, port_num=None):
480
485
481
486
482
487
@contextmanager
483
- def session (ansys_em_root , port_num , ip_address = None ):
488
+ def session (ansys_em_root : str , port_num : int = None , ip_address : str = None ):
484
489
r"""Launch a local session to an EDB API server in a context manager.
485
490
486
491
Parameters
487
492
----------
488
493
ansys_em_root : str
489
494
Directory where the ``EDB_RPC_Server.exe`` file is installed.
490
- port_num : int
491
- Port number to listen on.
495
+ port_num : int, default: None
496
+ Port number to listen on. The default is ``None``, in which case a port in [50051, 60000]
497
+ is selected.
492
498
ip_address : str, default: None
493
499
IP address where the server executable file is running. The default is ``None``, in which
494
500
case localhost is used.
@@ -573,3 +579,22 @@ def _ensure_session(ansys_em_root, port_num, ip_address):
573
579
else :
574
580
MOD .current_session = _Session (ip_address , port_num , ansys_em_root )
575
581
MOD .current_session .connect ()
582
+
583
+
584
+ def _find_available_port (interface : str = None , start_port : int = 50051 , end_port : int = 60000 ):
585
+ """Find an available port in the given range.
586
+
587
+ Parameters
588
+ ----------
589
+ interface : str, default: :data:`DEFAULT_ADDRESS`
590
+ Interface to check for available ports.
591
+ start_port : int, default: ``50051``
592
+ First port number to check.
593
+ end_port : int, default: ``60000``
594
+ Last port number to check.
595
+ """
596
+ for port in range (start_port , end_port ):
597
+ with socket .socket (socket .AF_INET , socket .SOCK_STREAM ) as sock :
598
+ if sock .connect_ex ((interface or DEFAULT_ADDRESS , port )) == errno .ECONNREFUSED :
599
+ return port
600
+ raise RuntimeError ("No available ports found" )
0 commit comments