1
1
from typing import Optional , Tuple , Union
2
+ import socket
3
+ from functools import lru_cache
2
4
3
- from ray ._raylet import build_address as _build_address
4
- from ray ._raylet import parse_address as _parse_address
5
+ from ray ._raylet import (
6
+ build_address as _build_address ,
7
+ is_ipv6_ip as _is_ipv6_ip ,
8
+ node_ip_address_from_perspective as _node_ip_address_from_perspective ,
9
+ parse_address as _parse_address ,
10
+ )
5
11
6
12
7
13
def parse_address (address : str ) -> Optional [Tuple [str , str ]]:
@@ -29,6 +35,65 @@ def build_address(host: str, port: Union[int, str]) -> str:
29
35
return _build_address (host , port )
30
36
31
37
38
+ def node_ip_address_from_perspective (address : str = "" ) -> str :
39
+ """IP address by which the local node can be reached *from* the `address`.
40
+
41
+ If no address is given, defaults to public DNS servers for detection. For
42
+ performance, the result is cached when using the default address (empty string).
43
+ When a specific address is provided, detection is performed fresh every time.
44
+
45
+ Args:
46
+ address: The IP address and port of any known live service on the
47
+ network you care about.
48
+
49
+ Returns:
50
+ The IP address by which the local node can be reached from the address.
51
+ """
52
+ return _node_ip_address_from_perspective (address )
53
+
54
+
55
+ def is_ipv6_ip (ip : str ) -> bool :
56
+ """Check if an IP string is IPv6 format.
57
+
58
+ Args:
59
+ ip: The IP address string to check (must be pure IP, no port).
60
+
61
+ Returns:
62
+ True if the IP is IPv6, False if IPv4.
63
+ """
64
+ return _is_ipv6_ip (ip )
65
+
66
+
67
+ @lru_cache (maxsize = 1 )
68
+ def get_localhost_address () -> str :
69
+ """Get localhost loopback address with IPv4/IPv6 support.
70
+
71
+ Returns:
72
+ The localhost loopback IP address (matching node IP family or auto-detected).
73
+ """
74
+ import ray ._private .worker
75
+
76
+ if (
77
+ ray ._private .worker ._global_node is not None
78
+ and ray ._private .worker ._global_node .node_ip_address
79
+ ):
80
+ node_ip = ray ._private .worker ._global_node .node_ip_address
81
+ return "::1" if is_ipv6_ip (node_ip ) else "127.0.0.1"
82
+
83
+ # Try IPv4 first, then IPv6 localhost resolution
84
+ for family in [socket .AF_INET , socket .AF_INET6 ]:
85
+ try :
86
+ dns_result = socket .getaddrinfo (
87
+ "localhost" , None , family , socket .SOCK_STREAM
88
+ )
89
+ return dns_result [0 ][4 ][0 ]
90
+ except socket .gaierror :
91
+ continue
92
+
93
+ # Final fallback to IPv4 loopback
94
+ return "127.0.0.1"
95
+
96
+
32
97
def is_localhost (host : str ) -> bool :
33
98
"""Check if the given host string represents a localhost address.
34
99
@@ -39,3 +104,29 @@ def is_localhost(host: str) -> bool:
39
104
True if the host is a localhost address, False otherwise.
40
105
"""
41
106
return host in ("localhost" , "127.0.0.1" , "::1" )
107
+
108
+
109
+ def create_socket (socket_type : int = socket .SOCK_STREAM ) -> socket .socket :
110
+ """Create a Python socket object with the appropriate family based on the node IP.
111
+
112
+ This function automatically gets the node IP address and creates a socket
113
+ with the correct family (AF_INET for IPv4, AF_INET6 for IPv6).
114
+
115
+ Args:
116
+ socket_type: The socket type (socket.SOCK_STREAM, socket.SOCK_DGRAM, etc.).
117
+
118
+ Returns:
119
+ A Python socket.socket object configured for the node's IP family.
120
+
121
+ Example:
122
+ # Create a TCP socket for the current node
123
+ sock = create_socket()
124
+
125
+ # Create a UDP socket for the current node
126
+ sock = create_socket(socket.SOCK_DGRAM)
127
+ """
128
+ node_ip = node_ip_address_from_perspective ()
129
+ family = socket .AF_INET6 if is_ipv6_ip (node_ip ) else socket .AF_INET
130
+
131
+ # Create socket directly with Python socket API
132
+ return socket .socket (family , socket_type )
0 commit comments