10.3 Networking MultipleClients C
10.3 Networking MultipleClients C
Multiple Clients
●
How can one program handle (very?) many requests?
– Specifically a server handle many TCP clients?
25-03-23 2
TCP Server Recap
●
Recall that on a TCP server:
– We open the first socket and call accept()
– accept() will return
file descriptor for
.. a brand new sochet
the new
client
●
How can we make our server work with multiple client
connection
sockets?
25-03-23 3
Idea 1: Thread per Connection
●
Idea 1: Thread
por connection
.. server
trad child process for each
–
creates a new
cusfited
– This thread handles the new client's socket. connection
●
Pros:
– Handle multiple clients cleanly. For multiple child process
Enreads lighter tran isolated
Cons:
are
can le
memory
● processes
– .. crushing one doesn't apput
Higher ou
head others
processes / threads ↓
creation
du to
of nu
Beet
is navy
on
memory
25-03-23 4
sockies
●
– .. mediately If To is not
create an
array of open posible
– General Idea: &
pull with
Server will infinitely loop through calling: non-blocking
alls
●
non-blocking-accept to add any new socket to array
●
non-blocking-read or non-bloccking-write (or both)
on each socket in array as needed
– Pros: Avoids creating new processes/threads This is
>
- called
– Cons: .. Loop keeps Chucking all sochets .
25-03-23
It's a
busy-wait loop .
polling 5
=>>
Error
25-03-23 6
• Busy-wait = You keep asking every table: “Are you ready to order?” (wasting time).
• I/O multiplexing = Customers raise a flag (kernel tells you): “Hey, I’m ready now!”
Idea 3: (cont)
●
Generally speaking, this is how I/O multiplexing works:
– We add file descriptors to the monitored list.
– We indicate what events we want to monitor the file
descriptors for, e.g., read and write.
– We call the blocking function to wait for an event,
e.g., select() or epoll()
– When it returns, check which file descriptors can perform I/O.
– We perform the I/O.
●
Pros:
– No thread overhead, no polling.
●
Cons:
– .. Code becomes more complex, to maintain a list
of
file descriptors to monitor
25-03-23 7
Idea 3: Implementing Sketch with epoll
●
3 Calls to implement I/O Multiplexing with epoll():
epoll_create()
– Returns an epoll instance.
– We can think of this as a
..
monitoring object that maintains the
monitoring list
epoll_ctl()
– Allows us to
.. Add remove
, or
modify a
file descriptor to spoll instance
●
Start by monitoring socket for accept()
●
Each new FD from accept() is added to set to monitor
epoll_wait()
– Waits for a file descriptor to be available for I/O
2) int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
• The kernel fills this with FDs that have pending I/O.
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <unistd.h>
#define handle_error(msg) \
do { \
perror(msg); \
exit(EXIT_FAILURE); \
} while (0)
int main() {
struct sockaddr_in addr, remote_addr;
int sfd, cfd, epollfd;
int nfds;
ssize_t num_read;
socklen_t addrlen = sizeof(struct sockaddr_in);
char buf[BUF_SIZE];
struct epoll_event ev, events[MAX_EVENTS];
epollfd = epoll_create1(0);
if (epollfd == -1)
handle_error("epoll_create1");
for (;;) {
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1)
handle_error("epoll_wait");
// Set O_NONBLOCK
int flags = fcntl(cfd, F_GETFL, 0);
if (flags == -1)
handle_error("fcntl");
flags |= O_NONBLOCK;
if (fcntl(cfd, F_SETFL, flags) == -1)
handle_error("fcntl");
if (num_read == -1)
handle_error("read");
ABCD: Server choices
●
Match the server implementation idea with
the problem it suffers:
1) Non-blocking IO in a loop
2) epoll() to watch sockets
3) Thread per client
25-03-23 9
Summary
●
accept() returns a new socket for each TCP client.
●
Server must likely handle many sockets at once:
– Can create a new thread per socket.
– Can use non-blocking IO to busy-wait checking for ready
sockets
– Can use epoll() or select() to have kernel monitor sockets
25-03-23 10
Summary
●
accept() returns a new socket for each TCP client.
●
Server must likely handle many sockets at once:
– Can create a new thread per socket.
– Can use non-blocking IO to busy-wait checking for ready
sockets
– Can use epoll() or select() to have kernel monitor sockets
25-03-23 10