Skip to content

Perl Socket Programming

Socket programming allows processes to communicate over a network, whether on the same machine or across different machines. Perl provides robust support for network programming through its built-in Socket module and various CPAN modules.

A socket is one endpoint of a two-way communication link between two programs running on a network. It’s an abstraction that combines an IP address (identifying a machine) and a port number (identifying a specific application or service on that machine). For example, web servers typically listen on port 80 (HTTP) or 443 (HTTPS).

Perl’s Socket module provides functions and constants for creating and managing sockets, based on the Berkeley Sockets API.

A common pattern in socket programming is the client-server model:

Server Steps:

  1. Create a socket: Using socket().
  2. Bind the socket: Associate the socket with a specific IP address and port on the server machine using bind().
  3. Listen for connections: Put the socket in a listening state to accept incoming client connections using listen().
  4. Accept connections: When a client attempts to connect, accept the connection using accept(). This typically creates a new socket dedicated to communication with that specific client.

Client Steps:

  1. Create a socket: Using socket().
  2. Connect to the server: Establish a connection to the server’s IP address and port using connect().

Once the connection is established, client and server can exchange data using functions like send() and recv(), or standard Perl I/O operations on the socket handle (e.g., print SOCKET $data; and $line = <SOCKET>;).

Core Socket Functions (from Socket module)

Section titled “Core Socket Functions (from Socket module)”

Always start your socket programs with use Socket; to import necessary functions and constants.

1. socket(SOCKET_HANDLE, DOMAIN, TYPE, PROTOCOL)

Section titled “1. socket(SOCKET_HANDLE, DOMAIN, TYPE, PROTOCOL)”

Creates a socket and associates it with SOCKET_HANDLE (a filehandle).

  • DOMAIN: Address family. PF_INET (or AF_INET) for IPv4. PF_INET6 (or AF_INET6) for IPv6.
  • TYPE: Socket type. SOCK_STREAM for TCP (reliable, connection-oriented). SOCK_DGRAM for UDP (unreliable, connectionless).
  • PROTOCOL: Protocol number. Often 0 to let the system choose, or (getprotobyname('tcp'))[2] for TCP, (getprotobyname('udp'))[2] for UDP.
Example: `socket(my $socket_fh, PF_INET, SOCK_STREAM, (getprotobyname('tcp'))[2]) or die "socket: $!";`

2. bind(SOCKET_HANDLE, PACKED_ADDRESS) (Server-side)

Section titled “2. bind(SOCKET_HANDLE, PACKED_ADDRESS) (Server-side)”

Assigns a local address (IP and port) to the socket.

PACKED_ADDRESS is typically created using pack_sockaddr_in(PORT, IP_ADDRESS_BINARY) for IPv4. IP_ADDRESS_BINARY is often inet_aton('hostname_or_ip') or INADDR_ANY (to bind to all available network interfaces).

Example: `my $port = 7890;
my $packed_addr = pack_sockaddr_in($port, INADDR_ANY);
bind($server_fh, $packed_addr) or die "bind: $!";`

3. listen(SOCKET_HANDLE, QUEUE_SIZE) (Server-side)

Section titled “3. listen(SOCKET_HANDLE, QUEUE_SIZE) (Server-side)”

Marks the socket as a passive socket that will be used to accept incoming connection requests. QUEUE_SIZE is the maximum number of pending connections.

Example: `listen($server_fh, 5) or die "listen: $!";` (5 is a common backlog size)

4. accept(NEW_SOCKET_HANDLE, LISTENING_SOCKET_HANDLE) (Server-side)

Section titled “4. accept(NEW_SOCKET_HANDLE, LISTENING_SOCKET_HANDLE) (Server-side)”

Extracts the first connection request on the queue of pending connections for LISTENING_SOCKET_HANDLE, creates a new connected socket, and associates it with NEW_SOCKET_HANDLE. This call blocks until a connection is available.

Example: `my $client_addr = accept(my $client_fh, $server_fh) or die "accept: $!";`
`$client_addr` will contain the packed address of the connected client.

5. connect(SOCKET_HANDLE, PACKED_SERVER_ADDRESS) (Client-side)

Section titled “5. connect(SOCKET_HANDLE, PACKED_SERVER_ADDRESS) (Client-side)”

Establishes a connection to a server at PACKED_SERVER_ADDRESS.

Example: `my $server_host = 'localhost';
my $server_port = 7890;
my $server_ip_bin = inet_aton($server_host) or die "Cannot resolve $server_host";
my $packed_server_addr = pack_sockaddr_in($server_port, $server_ip_bin);
connect($client_fh, $packed_server_addr) or die "connect: $!";`

Here’s a basic example where a server sends a greeting to a client.

#!/usr/bin/perl
use strict;
use warnings;
use Socket;
use POSIX 'WNOHANG'; # For non-blocking check of child processes
my $port = shift || 7890;
my $protocol = getprotobyname('tcp');
# Create socket
socket(my $listen_fh, PF_INET, SOCK_STREAM, $protocol)
or die "Can't create socket: $!";
# Allow address reuse
setsockopt($listen_fh, SOL_SOCKET, SO_REUSEADDR, 1)
or die "Can't set SO_REUSEADDR: $!";
# Bind to port
my $server_addr = pack_sockaddr_in($port, INADDR_ANY);
bind($listen_fh, $server_addr)
or die "Can't bind to port $port: $!";
# Listen for connections
listen($listen_fh, SOMAXCONN) # SOMAXCONN is system's max queue size
or die "Can't listen on port $port: $!";
print "Server started on port $port, waiting for connections...\n";
# Handle child process termination to prevent zombies
$SIG{CHLD} = sub {
while (waitpid(-1, WNOHANG) > 0) {
# Child reaped
}
};
while (1) {
my $client_packed_addr = accept(my $client_fh, $listen_fh);
unless (defined $client_packed_addr) {
warn "accept failed: $!";
next;
}
# Get client info for logging
my ($client_port, $client_ip_bin) = unpack_sockaddr_in($client_packed_addr);
my $client_ip_str = inet_ntoa($client_ip_bin);
print "Connection from $client_ip_str:$client_port\n";
# Fork a child process to handle this client
my $pid = fork();
die "Cannot fork: $!" unless defined $pid;
if ($pid == 0) { # Child process
close $listen_fh; # Child doesn't need the listening socket
# Send a greeting
print $client_fh "Hello from Perl Server!\n";
print "Sent greeting to $client_ip_str:$client_port\n";
# Example: Read a line from client
my $client_message = <$client_fh>;
if (defined $client_message) {
chomp $client_message;
print "Received from $client_ip_str: '$client_message'\n";
}
close $client_fh;
exit 0; # Child exits
} else { # Parent process
close $client_fh; # Parent closes the client connection handle
# Parent continues to listen for new connections
}
}
close $listen_fh;
#!/usr/bin/perl
use strict;
use warnings;
use Socket;
my $host = shift || 'localhost';
my $port = shift || 7890;
my $protocol = getprotobyname('tcp');
# Resolve server address
my $server_ip_bin = inet_aton($host)
or die "Cannot resolve hostname '$host': $!";
my $server_addr = pack_sockaddr_in($port, $server_ip_bin);
# Create socket
socket(my $client_fh, PF_INET, SOCK_STREAM, $protocol)
or die "Can't create socket: $!";
# Connect to server
connect($client_fh, $server_addr)
or die "Can't connect to $host:$port: $!";
print "Connected to server $host:$port\n";
# Read greeting from server
my $server_response = <$client_fh>;
if (defined $server_response) {
print "Server says: $server_response";
} else {
print "No response from server or connection closed.\n";
}
# Example: Send a message to server
print $client_fh "Hi Server, this is Client!\n";
close $client_fh or warn "close failed: $!";
print "Connection closed.\n";

To Run:

  1. Save the server code as server.pl and client code as client.pl.
  2. Open a terminal and run the server: perl server.pl
  3. Open another terminal and run the client: perl client.pl

You should see the server acknowledge the connection and the client print the server’s greeting.

This server uses fork() to handle multiple clients concurrently. For more advanced scenarios (non-blocking I/O, threading), modules like IO::Async, Mojo::IOLoop (from Mojolicious), or AnyEvent are commonly used.

Socket programming can be complex. Key areas for further study include:

  • Error Handling: Robust error checking is crucial.
  • UDP Sockets: For connectionless communication.
  • Non-blocking I/O: To handle multiple connections without forking/threading for every client.
  • Serialization: Converting complex data structures for network transmission (e.g., using JSON, Sereal, Storable).
  • Security: SSL/TLS for encrypted communication (e.g., using IO::Socket::SSL).

Consult perldoc Socket, perldoc perlipc (for inter-process communication, including sockets), and perldoc perlfunc for detailed information on related functions.