NET-2: Multiplexed Sqrt Server
Requirements
-
Write a C/C++ TCP server program that:
- Creates a TCP socket and binds it to a specified port (default: 8080)
- Listens for incoming client connections
- Uses
epollto handle multiple simultaneous clients in a single thread — nofork(), no threads - All sockets (listening and client) must be set to non-blocking mode (
O_NONBLOCK) - For each connected client:
- Reads exactly 4 bytes representing a signed 32-bit integer (
int32_t) in network byte order - Computes
f(x) = sqrt(abs(x))and sends the result back as an 8-byte IEEE 754 double in network byte order - Handles the case where the client sends multiple requests over the same connection
- Detects client disconnection and removes the descriptor from the epoll instance
- Reads exactly 4 bytes representing a signed 32-bit integer (
- Prints a log line when a client connects or disconnects, and for each request processed
- Runs indefinitely until terminated with Ctrl+C
-
Write a C/C++ TCP client program that:
- Connects to the server at a specified IP address and port
- Reads an integer from
stdin, sends it to the server as a 4-byte network-orderint32_t - Receives the 8-byte
doubleresponse and prints the result - Repeats until
EOF(Ctrl+D) or the user typesexit
-
Both programs must use the BSD socket API and proper byte order conversion
-
Handle all system call errors — check every return value
Expected result
The resulting applications should be able to build and execute from command line as follows:
make
./sqrt-server 8080In separate terminals, run multiple clients simultaneously:
./sqrt-client 127.0.0.1 8080Server terminal output:
[Server] Listening on port 8080 (epoll, non-blocking)
[Server] Client connected: 127.0.0.1:54321 (fd=5)
[Server] Client connected: 127.0.0.1:54322 (fd=6)
[Server] fd=5 recv: -16 -> sqrt(abs(-16)) = 4.000000
[Server] fd=6 recv: 225 -> sqrt(abs(225)) = 15.000000
[Server] fd=5 recv: 0 -> sqrt(abs(0)) = 0.000000
[Server] Client disconnected: fd=5
Client terminal output:
[Client] Connected to 127.0.0.1:8080
> -16
[Server]: sqrt(abs(-16)) = 4.000000
> 225
[Server]: sqrt(abs(225)) = 15.000000
> exit
[Client] Disconnecting...
Notes
- Use
epoll_create1(EPOLL_CLOEXEC)to create the epoll instance - Use level-triggered mode (default) — no need for edge-triggered for this task
doublehas no standard network byte order representation — use a byte-swap approach or send as raw bytes with a defined endianness (document your choice)sqrtandfabsare in<math.h>/<cmath>; link with-lmif needed
Bonus (Optional)
- Switch to edge-triggered mode (
EPOLLET) and implement the full draining loop for reads - Support an arbitrary number of requests per connection with a per-client receive buffer to handle partial reads correctly
- Add a timeout: disconnect clients that send no request within 30 seconds (use
epoll_waittimeout ortimerfd) - Report the number of active connections when receiving
SIGUSR1
Deliverables
The final solution should contain a Makefile for building both programs. The Makefile should contain targets:
all— build both server and clientsqrt-server— build only the serversqrt-client— build only the clientclean— remove compiled binaries
It’s recommended to have the compiler and compiler flags declared as Makefile variables. Alternatively, cmake could also be used instead of make.