Fundamentals of Socket Programming
Socket Programming Interface
The socket() Function
The function signature is:
#include <sys/types.h>
#include <sys/socket.h>
int socket(int domain, int type, int protocol);
The socket() function behaves similarly to open(), creating a communication endpoint for network interaction. On success, it returns a file descriptor, commonly referred to as a socket descriptor. This descriptor functions like a regular file descriptor.
- domain: Specifies the communication domain, determining the protocol family used for communication. For TCP/IP applications,
AF_INETis typically chosen. - type: Defines the socket type.
- protocol: Usually set to 0, indicating the default protocol for the specified domain.
Example usage:
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("socket creation failed");
exit(EXIT_FAILURE);
}
...
close(sock);
The bind() Function
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
The bind() function associates a IP address or port with a socket. It binds the socket identified by sockfd to the address specified by addr. Returns zero on success, or -1 on failure, setting errno accordingly.
The generic sockaddr structure is defined as:
struct sockaddr {
sa_family_t sa_family;
char sa_data[14];
};
The sa_data array holds addressing information, but it's not user-friendly due to its opaque nature. In practice, developers use sockaddr_in, which is more convenient and compatible with sockaddr.
struct sockaddr_in {
sa_family_t sin_family;
in_port_t sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
Usage example:
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(5555);
bind(sock, (struct sockaddr *)&addr, sizeof(addr));
The listen() Function
int listen(int sockfd, int backlog);
The accept() Function
After calling listen(), the server enters a listening state, waiting for client connection requests. The accept() function retrieves these requests and establishes connections. Its prototype is:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
A server typically follows these steps:
- Create a socket using
socket(). - Bind the socket to an address with
bind(). - Start lisetning with
listen()for incoming connections. - Accept connections using
accept().
The connect() Function
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
This function is used by clients to establish a connection to a remote server. For TCP connections, it initiates a handshake process. For UDP, it merely records the server's address without sending data.
Sending and Receiving Data
The recv() Function
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
The send() Function
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
Closing the Socket
Use close() to release socket resources.