Of course! The getnameinfo() function in Python is part of the built-in socket module. It's a powerful tool for performing reverse lookups on network addresses.

While getaddrinfo() takes a name (like "google.com") and finds its IP addresses, getnameinfo() does the opposite: it takes an IP address and port number and tries to find the corresponding host name and service name.
What is getnameinfo()?
The getnameinfo() function performs a two-part reverse lookup:
- Host Name Resolution: It takes an IP address and resolves it back to a hostname (e.g.,
8.8.8->"dns.google"). - Service Name Resolution: It takes a port number and resolves it to a service name (e.g.,
80->"http").
It's the reverse of the more commonly used getaddrinfo().
Function Signature
socket.getnameinfo(sockaddr, flags)
Parameters
-
sockaddr: A tuple representing the network address. The format depends on the address family:
(图片来源网络,侵删)- For IPv4/AF_INET:
(ip_address, port) - For IPv6/AF_INET6:
(ip_address, port, flow_info, scope_id) - You can get this tuple directly from a socket's
getpeername()orgetsockname()methods.
- For IPv4/AF_INET:
-
flags: An integer that controls the behavior of the function. You can combine multiple flags using the bitwise OR operator (). The most common flags are:socket.NI_NAMEREQD: If the hostname cannot be found, raise an error instead of returning the IP address. This is useful if you require a hostname.socket.NI_DGRAM: The service is a datagram service (like UDP). This is important for ports that can be used for both TCP and UDP (e.g., 512).socket.NI_NOFQDN: Return only the hostname part, not the fully qualified domain name (FQDN). For example, return"myhost"instead of"myhost.mydomain.com".socket.NI_NUMERICHOST: Do not resolve the hostname; return the IP address as a string.socket.NI_NUMERICSERV: Do not resolve the service name; return the port number as a string.
Return Value
It returns a tuple of two strings: (hostname, servicename)
Practical Examples
Let's walk through a few common use cases.
Example 1: Basic Reverse DNS Lookup
This is the most straightforward use case: finding the hostname for a given IP and port.
import socket
# A well-known public DNS server
ip_address = "8.8.8.8"
port = 53 # DNS port
# The sockaddr tuple for an IPv4 address
sockaddr = (ip_address, port)
try:
# Perform the lookup with default flags
hostname, service = socket.getnameinfo(sockaddr, 0)
print(f"IP: {ip_address}, Port: {port}")
print(f"Resolved Hostname: {hostname}")
print(f"Resolved Service: {service}")
except socket.gaierror as e:
print(f"Lookup failed: {e}")
# --- Output ---
# IP: 8.8.8.8, Port: 53
# Resolved Hostname: dns.google
# Resolved Service: domain
Example 2: Using Flags to Control Behavior
Flags let you fine-tune the behavior. Let's see what happens when we use NI_NUMERICHOST and NI_NUMERICSERV.
import socket
ip_address = "8.8.8.8"
port = 53
sockaddr = (ip_address, port)
# Use flags to prevent name resolution
flags = socket.NI_NUMERICHOST | socket.NI_NUMERICSERV
try:
hostname, service = socket.getnameinfo(sockaddr, flags)
print(f"IP: {ip_address}, Port: {port}")
print(f"Hostname (numeric): {hostname}")
print(f"Service (numeric): {service}")
except socket.gaierror as e:
print(f"Lookup failed: {e}")
# --- Output ---
# IP: 8.8.8.8, Port: 53
# Hostname (numeric): 8.8.8.8
# Service (numeric): 53
As you can see, it returned the original IP and port instead of resolving them.
Example 3: Error Handling with NI_NAMEREQD
Sometimes, you want to ensure you get a valid hostname and don't want to fall back to an IP address. NI_NAMEREQD is perfect for this.
import socket
# An IP address that is unlikely to have a reverse DNS entry
ip_address = "159.223.0.1"
port = 80
sockaddr = (ip_address, port)
print("--- Without NI_NAMEREQD (default behavior) ---")
try:
# Default behavior will return the IP if hostname lookup fails
hostname, service = socket.getnameinfo(sockaddr, 0)
print(f"Resolved Hostname: {hostname}")
except socket.gaierror as e:
print(f"Lookup failed: {e}")
print("\n--- With NI_NAMEREQD ---")
try:
# This will raise an error if the hostname cannot be found
hostname, service = socket.getnameinfo(sockaddr, socket.NI_NAMEREQD)
print(f"Resolved Hostname: {hostname}")
except socket.gaierror as e:
print(f"Lookup failed as expected: {e}")
# --- Output ---
# --- Without NI_NAMEREQD (default behavior) ---
# Resolved Hostname: 159.223.0.1
#
# --- With NI_NAMEREQD ---
# Lookup failed as expected: [Errno 8] nodename nor servname provided, or not known
Example 4: Using with a Connected Socket
A very practical use case is to find out who you are connected to after a socket connection has been made.
import socket
# Connect to a well-known service
HOST = "google.com"
PORT = 80 # HTTP
try:
# Create a socket and connect
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
s.connect((HOST, PORT))
# Get the socket's peer address (the server we connected to)
peer_addr = s.getpeername()
print(f"Connected to: {peer_addr}")
# Use getnameinfo to resolve the peer's address
hostname, service = socket.getnameinfo(peer_addr, 0)
print(f"Peer Hostname: {hostname}")
print(f"Peer Service: {service}")
except socket.gaierror as e:
print(f"Name resolution failed: {e}")
except socket.error as e:
print(f"Socket error: {e}")
# --- Sample Output ---
# Connected to: ('142.250.199.100', 80)
# Peer Hostname: fra16s07-in-f100.1e100.net
# Peer Service: http
Common Pitfalls and Best Practices
-
gaierror: This is the most common exception you'll encounter. It means the address resolution failed. This can happen for many reasons:- The IP address genuinely has no reverse DNS entry.
- The DNS server you are using is not configured for reverse lookups.
- Network connectivity issues.
- The port number is invalid.
-
Performance: DNS lookups are not instantaneous. They involve a network request to a DNS server. In performance-critical applications, you might want to cache the results of
getnameinfo()calls to avoid repeated lookups for the same IP. -
Unreversable IPs: Many IPs, especially those in data centers or from consumer ISPs, do not have valid reverse DNS entries. Your code should be prepared to handle this gracefully, especially if you are not using
NI_NAMEREQD.
getnameinfo() vs. getaddrinfo()
It's crucial to understand the difference:
| Feature | socket.getaddrinfo() |
socket.getnameinfo() |
|---|---|---|
| Purpose | Forward Lookup: Name -> IP(s) | Reverse Lookup: IP/Port -> Name(s) |
| Input | A hostname and optional port/service | A sockaddr tuple (IP, port) |
| Output | A list of 5-tuples with address info | A 2-tuple with (hostname, servicename) |
| Common Use | Resolving a domain name before connecting to a server. | Identifying a connection partner after a connection is made. |
In summary, getnameinfo() is an essential function for network programming when you need to translate network addresses back into human-readable names and service descriptions.
