Socketpair program using Poll System Call
In this program, you are going to learn
How to create a socket ?
How to create a fork ?
How to send a data ?
How to recv a data?
Let us answer few basic questions in this socket
Why use socketpair
in the program?
See Answer
socketpair
creates a pair of connected sockets in the specified domain, allowing communication between processes.
What parameters does socketpair take?
See Answer
socketpair(domain, type, protocol, sv)
, where domain is typically AF_UNIX
for local communication.
Why use AF_UNIX
as the domain for socketpair?
See Answer
AF_UNIX
is suitable for local communication within the same system.
What is the significance of SOCK_STREAM
as the socket type?
See Answer
SOCK_STREAM
provides a reliable, connection-oriented communication channel.
Can socketpair
be used for network communication?
See Answer
No, socketpair
is designed for local communication between processes on the same system.
Why is protocol
often specified as 0
in the socketpair
call?
See Answer
protocol
is typically set to 0 to allow the system to choose the default protocol for the specified domain and type.
What is the purpose of the sv
array in the socketpair
call?
See Answer
It holds the file descriptors for the created sockets.
How does socketpair
handle errors during execution?
See Answer
It returns -1
on error, and you can use perror
to print an error message.
Can the created sockets be used for communication between unrelated processes?
See Answer
No, socketpair is typically used for communication between related processes (e.g., parent and child).
Can the created sockets be passed between processes using fork
?
See Answer
Yes, both the parent and child processes have access to the created sockets.
How does socketpair
differ from other socket
creation functions like socket?
See Answer
socketpair
creates a pair of connected sockets
, while socket creates a single socket for network communication.
How is data sent
from the parent to the child process?
See Answer
The parent
uses the send
function to transmit data over the socket pair.
How is data received by the child process?
See Answer
The child
uses the recv
function to receive data from the parent.
Why is close
called for each socket in both parent and child processes?
See Answer
close
is used to close unnecessary file descriptors, releasing resources.
What is the purpose of the poll system call?
See Answer
To block and wait for activity on one or more file descriptors.
How does poll differ from poll in terms of usability?
See Answer
poll is more efficient than poll for monitoring multiple file descriptors.
What types of file descriptors can be monitored using poll?
See Answer
sockets, files, timerfd, socketpair, message_queue, Namedpipes and shared_memory.
How does poll handle a set of file descriptors with different states (e.g., reading, writing, exception)?
See Answer
It uses different structures for each state in the pollfd array.
How do you handle errors when using the poll system call?
See Answer
Check the return value for -1 to detect errors, Use perror to print error messages.
How does poll handle a set of file descriptors with different states (e.g., reading, writing, exception)?
See Answer
- Array of pollfd Structures:
Before calling poll, you need to create an array of pollfd structures, where each structure represents a file descriptor and its associated events.
struct pollfd fds[NUM_FDS];
NUM_FDS is the number of file descriptors you want to monitor.
- Initialize pollfd Structures:
For each file descriptor you want to monitor, initialize the corresponding pollfd structure with the following information:
fd: The file descriptor to monitor. events: The events of interest (e.g., POLLIN for readability, POLLOUT for writability). revents: Initially set to zero. After the poll call, this field is updated to indicate the events that occurred.
fds[0].fd = fd1;
fds[0].events = POLLIN;
fds[0].revents = 0;
fds[1].fd = fd2;
fds[1].events = POLLIN;
fds[1].revents = 0;
- Call poll:
After initializing the pollfd array, call the poll function, providing the array, the number of file descriptors, and a timeout
int ready_fds = poll(fds, NUM_FDS, timeout_ms);
ready_fds will contain the number of file descriptors that are ready.
How does poll Checking Ready File Descriptors?
See Answer
After the poll call, loop through the pollfd array and check the revents field for each file descriptor to determine which events occurred.
for (int i = 0; i < NUM_FDS; ++i) {
if (fds[i].revents & POLLIN) {
// File descriptor i is ready for reading
}
if (fds[i].revents & POLLOUT) {
// File descriptor i is ready for writing
}
// Check other events if needed (e.g., POLLERR, POLLHUP)
}
What does it mean if poll returns 0?
See Answer
No file descriptors are ready within the specified timeout.
There are many functions used in socketpair. We can classify those functions based on functionalities.
Create Socket
Fork
Poll
Recv data_packet
Send data_packet
Close socket
socketpair
creates a pair of connected sockets for local inter-process communication. For example,
sockfd = socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
fork
creates a child process, and both the parent and child processes can communicate through the socket pair. For example,
pid_t pid = fork();
poll()
is used for monitoring multiple file descriptors to see if I/O is possible on any of them.
ret = poll(fds, 1, -1);
recv
is used in network programming to receive data from a connected socket. For example,
ret = recv(sv[1], buffer, sizeof(buffer), 0);
send
is used in network programming to send data over a connected socket. For example,
ret = send(sv[0], buffer, strlen(buffer), 0);
close
is used to close the socket To free up system resources associated with the socket. For example,
(void)close(sv[0]);
(void)close(sv[1]);
See the full program below,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <signal.h>
#include <poll.h>
#define BUFFER_SIZE 1024
int sv[2];
static void sigint_handler(
int signo)
{
(void)close(sv[0]);
(void)close(sv[1]);
sleep(2);
(void)printf("Caught sigINT!\n");
exit(EXIT_SUCCESS);
}
void register_signal_handler(
int signum,
void (*handler)(int))
{
if (signal(signum, handler) ==
SIG_ERR) {
printf("Cannot handle signal\n");
exit(EXIT_FAILURE);
}
}
int main()
{
int sockfd;
int ret;
struct pollfd fds[1];
char buffer[BUFFER_SIZE];
register_signal_handler(SIGINT,
sigint_handler);
sockfd = socketpair(AF_UNIX,
SOCK_STREAM, 0, sv);
if (sockfd < 0) {
perror("socketpair");
return -1;
}
printf("Socket pair created\n");
pid_t pid = fork();
if (pid == -1) {
perror("fork");
return -2;
}
if (pid == 0) {
// Child process (Server)
(void)close(sv[0]);
fds[0].fd = sv[1];
fds[0].events = POLLIN;
while (1) {
ret = poll(fds, 1, -1);
if (ret == -1) {
perror("poll");
break;
}
if (fds[0].revents & POLLIN) {
ret = recv(sv[1], buffer,
sizeof(buffer), 0);
if (ret < 0) {
perror("recv");
break;
}
buffer[ret] = '\0';
printf("Received from server: %s\n",
buffer);
}
}
(void)close(sv[1]);
} else {
// Parent process (Client)
(void)close(sv[1]);
while (1) {
memset(buffer, 0,
sizeof(buffer));
strncpy(buffer, "hello child",
strlen("hello child") + 1);
buffer[strlen(buffer) + 1] = '\0';
ret = send(sv[0], buffer,
strlen(buffer), 0);
if (ret < 0) {
perror("send");
break;
}
printf("Sending client buffer = %s\n",
buffer);
sleep(1);
}
}
(void)close(sv[0]);
(void)close(sv[1]);
return 0;
}
1$ gcc -o socketpair socketpair.c
2
3$ sudo ./socketpair
4
5Socket pair created
6Sending client buffer = hello child
7Received from server: hello child
8Sending client buffer = hello child
9Received from server: hello child
10Sending client buffer = hello child
11Received from server: hello child
12Sending client buffer = hello child
13Received from server: hello child
14Sending client buffer = hello child
15Received from server: hello child
16Sending client buffer = hello child
17Received from server: hello child
18Sending client buffer = hello child
19Received from server: hello child
20Sending client buffer = hello child
21Received from server: hello child
22Sending client buffer = hello child
23Received from server: hello child
24Sending client buffer = hello child
25Received from server: hello child
26^CCaught sigINT!
27Caught sigINT!
Socket API |
Learning |
---|---|
socketpair |
creates a pair of connected sockets for local inter-process communication. |
fork |
creates a child process, and both the parent and child processes can communicate through the socket pair. |
poll |
Monitor multiple file descriptors (usually sockets) for read, write, or error conditions. |
recv |
Receive data from a connected socket. |
send |
Send data over a connected socket. |
Previous topic
Current topic
Next IPC