Code:
/*
server_forked.c
---------------
Forked TCP server, each client is accepted by a separate process.
Client gets request echo until 'quit' is typed.
Compile with
gcc -oserver_forked server_forked.c
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/wait.h>
#include <signal.h>
/**
waits all children to finish
@param sig_no not used
@return none
**/
void wait_children(int sig_no)
{
while (waitpid((pid_t)-1, NULL, WNOHANG) > 0)
;
}
/**
processes one client
@param client_fd client socket
**/
void process(int client_fd)
{
const int REQUEST_LEN = 1000;
char request[REQUEST_LEN];
memset((void*)request, '\0', REQUEST_LEN);
while (strncmp(request, "quit", 4))
{
int result;
memset((void*)request, '\0', REQUEST_LEN);
result = recv(client_fd, request, REQUEST_LEN, 0);
if (result == -1)
{
fprintf(stderr, "process():getpid()=%d,cannot receive request,ending chat...\n", getpid());
break;
}
else if (result == 0)
{
printf("process():getpid()=%d,client quitted,ending chat...\n", getpid());
break;
}
printf("process():getpid()=%d,request=%s\n", getpid(), request);
if (send(client_fd, request, strlen(request), 0) == -1)
{
fprintf(stderr, "process():getpid()=%d,cannot send response,ending chat...\n", getpid());
break;
}
printf("process():getpid()=%d,echo sent...\n", getpid());
}
close(client_fd);
}
int main()
{
struct addrinfo* server_address;
struct addrinfo hint;
int server_fd = 0;
const char* PORT = "7000";
const unsigned int PENDING_SIZE = 5;
struct sigaction signal_action;
hint.ai_family = 0;
hint.ai_socktype = SOCK_STREAM;
hint.ai_flags = AI_PASSIVE;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_canonname = NULL;
hint.ai_addr = NULL;
hint.ai_next = NULL;
if (getaddrinfo("localhost", PORT, &hint, &server_address) != 0)
{
fprintf(stderr, "main():cannot locate host,exiting program...\n");
exit(EXIT_FAILURE);
}
server_fd = socket(server_address->ai_family, server_address->ai_socktype, server_address->ai_protocol);
if (server_fd == -1)
{
fprintf(stderr, "main():cannot create socket,exiting program...\n");
exit(EXIT_FAILURE);
}
if (bind(server_fd, server_address->ai_addr, server_address->ai_addrlen) == -1)
{
fprintf(stderr, "main():cannot bind,exiting program...\n");
exit(EXIT_FAILURE);
}
freeaddrinfo(server_address);
if (listen(server_fd, PENDING_SIZE) == -1)
{
fprintf(stderr, "main():cannot listen,exiting program...\n");
exit(EXIT_FAILURE);
}
signal_action.sa_handler = wait_children;
sigemptyset(&signal_action.sa_mask);
signal_action.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &signal_action, NULL) == -1)
{
fprintf(stderr, "main():'sigaction()' failed,exiting program...\n");
exit(EXIT_FAILURE);
}
while (1)
{
struct sockaddr client_address;
socklen_t client_address_len = sizeof(struct sockaddr_storage);
int client_fd;
char addr_buf[INET_ADDRSTRLEN];
int pid;
client_fd = accept(server_fd, &client_address, &client_address_len);
if (client_fd == -1)
{
printf("main():cannot accept client,sleeping...\n");
sleep(5);
}
printf("main():client accepted from:%s\n", inet_ntop(AF_INET, &client_address, addr_buf, INET_ADDRSTRLEN));
// fork child process for a new client
pid = fork();
if (pid == 0) // child
{
process(client_fd);
close(client_fd);
printf("main():ending child...\n");
exit(EXIT_SUCCESS);
}
else if (pid < 0)
{
fprintf(stderr, "main():cannot fork,sleeping...\n");
sleep(5);
}
close(client_fd);
}
return EXIT_SUCCESS;
}
When server socket is created, the forever loop in