getservbyport#
Look up a network service by its numeric port and protocol.
getservbyport consults the system services database (/etc/services
on Linux, plus whatever NSS sources are configured) and returns the
record for the service that listens on PORT under protocol PROTO.
PORT is an integer in network byte order — the value you would
pass to bind or receive from sockaddr_in,
not the decimal shown in /etc/services. PROTO is a lowercase string
such as "tcp" or "udp". The call wraps the C library’s
getservbyport(3).
Synopsis#
getservbyport PORT, PROTO # list context: full record
scalar getservbyport PORT, PROTO # scalar context: service name
What you get back#
In list context, a five-element list describing the service:
my ($name, $aliases, $port, $proto) = getservbyport($port_n, "tcp");
Index |
Name |
Meaning |
|---|---|---|
0 |
|
Canonical service name, e.g. |
1 |
|
Space-separated alias list, e.g. |
2 |
|
Port number in network byte order |
3 |
|
Protocol name, e.g. |
If the entry does not exist the list is empty, so a list-context
assignment leaves every target undef. A bare list-context
call returns a single meaningless true value on miss — always assign
to a list and test the first element, or call in scalar context.
In scalar context, you get the canonical service name (the same
$name as above), or undef if no service is registered on
that port for that protocol:
my $name = getservbyport($port_n, "tcp")
or warn "port $port not registered for tcp";
Global state it touches#
$!is not reliably set on a miss — the Cgetservbyport(3)function has no standard errno contract for “not found”. Treat an empty list orundefreturn as the only trustworthy failure signal.Iteration state held by the services database (shared with
getservent,setservent, andendservent) is process-global and not thread-safe.
Byte-order trap#
PORT must be network byte order. The port column in /etc/services
is a human decimal; the value the kernel and the C library use is the
big-endian 16-bit encoding. Convert with pack /
unpack or with the Socket helpers:
use Socket;
# Host decimal 80 -> network-order short:
my $port_n = pack("n", 80); # two bytes, big-endian
my @rec = getservbyport($port_n, "tcp");
# Or going the other way, a port extracted from sockaddr_in is
# already network order:
my ($port_n_from_peer, $iaddr) = sockaddr_in(getpeername($sock));
my $name = getservbyport($port_n_from_peer, "tcp");
Passing a host-order integer such as 80 works on little-endian
hardware only by accident for low ports whose encoding happens to be
non-zero in the low byte — most ports will simply miss. This is the
single most common reason a getservbyport call “silently returns
nothing”.
Examples#
Identify the service on port 443 over TCP:
use Socket;
my $port_n = pack("n", 443);
my ($name) = getservbyport($port_n, "tcp");
print $name, "\n"; # https
Pair with getpeername to name an incoming connection’s
port:
use Socket;
my ($peer_port_n, $peer_addr) = sockaddr_in(getpeername($client));
my $service = getservbyport($peer_port_n, "tcp") // "unknown";
print "client connected from service $service\n";
Full record dump — useful when you want the protocol or aliases:
use Socket;
my @rec = getservbyport(pack("n", 53), "udp");
if (@rec) {
my ($name, $aliases, $port_n, $proto) = @rec;
printf "%s (%s) on %d/%s\n",
$name, $aliases, unpack("n", pack("n", $port_n)), $proto;
}
Scalar context, guard clause style:
my $svc = getservbyport(pack("n", $port), "tcp")
or die "no TCP service registered on port $port";
Iterate every registered service (the underlying database is shared
with getservent):
while (my ($n, $a, $p, $proto) = getservent()) {
next unless $proto eq "tcp";
# …do something with $n / $p…
}
endservent();
Edge cases#
Missing entry: empty list in list context,
undefin scalar context. A bareif (getservbyport(...))in list context is truthy even for a missing entry because of the “single meaningless true value” legacy return — always assign to a list or force scalar context.Unknown protocol: an unrecognised
PROTOstring (e.g."sctp"on a host whose database does not include it) is treated by the C library as no-match. The call returns empty/undef, not an error.Case of
PROTO: case-sensitive on most Linux libc implementations. Use lowercase"tcp"/"udp";"TCP"will miss.Host-order port: passing
80instead ofpack("n", 80)is the classic bug — see Byte-order trap above.Numeric vs string
PORT: Perl numifiesPORTbefore passing to libc. A two-byte packed string works becausepackwith"n"produces bytes that numify deterministically on the supported platforms; if in doubt,unpack("n", $packed)first and pass the integer to keep the intent explicit.Precedence with list operators: like other named unary / list operators,
getservbyportbinds loosely. Parenthesise when the result feeds another operator:getservbyport $port_n, "tcp" eq "https" # WRONG (getservbyport($port_n, "tcp")) eq "https" # correct
Threads: the underlying lookup shares state with
getservent/setservent/endservent. Two threads iterating concurrently will interleave records. Use thread-local wrappers when that matters.
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
getservbyname— inverse lookup, service name to port; reach for it when you know the name and want the numbergetservent— iterate every service record; use when you need a full sweep rather than a single lookupsetservent— rewind the services iterator, optionalSTAYOPENflag to keep the file open acrossforkendservent— close the services database after an iterationgetprotobynumber— the protocol-side companion lookup; often used right aftergetservbyportto translate the$protofieldpack— build the network-order port valuegetservbyportexpects as its first argumentSocket— constants andsockaddr_inhelpers that produce network-order ports straight from kernel structures