I’m developing in C a Unix application consisting of a server that has to communicate simultaneously with at most five clients. Clients send to server a command which can be tuttomaiuscolo (alltoupper in english) or tuttominuscolo (alltolower) and a string to manipulate; the server receives the two strings and remove from the second word all the characters that are not a-z A-Z characters. If a client sends the string FINE (end) the server has to stop and die (whitout leaving zombie processes).
The problem is the connection between the client and the server. To do this I’ve used the function select in server and in client too, but the problem is that the select placed in the server (that monitors the reading) doesn’t see the client request, so it never goes to the accept function, while the client select (that monitors the writing) returns a value that means it is ready for writing.
Now I’ll post the code:
server:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <signal.h>
#include <wait.h>
#include <ctype.h>
void ripulisci (char* stringa);
void minuscola (char* orig, char* dest);
void maiuscola (char* orig, char* dest);
void handler(int);
int list;
int sock;
int main () {
int status;
//creo un socket da mettere in ascolto
list = socket (AF_INET, SOCK_STREAM, 0);
if (list < 0) {
perror("Error!");
exit(1);
}
//preparo la struct sockaddr_in
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(2770);
//effettuo il bind
status = bind(list, (struct sockaddr*) &address, sizeof(address));
if (status < 0) {
perror("Error!");
close(list);
exit(1);
}
//mi metto in ascolto
listen(list, 1);
printf("Attendo le connessioni...\n");
//preparo le variabili necessarie per gestire i figli
int esci = 1;
pid_t server[5];
char comando[15];
char lettura[512];
char scrittura[512];
struct sockaddr_in client;
int client_size = sizeof(client);
fd_set fd;
FD_ZERO(&fd);
FD_SET(list, &fd);
struct timeval timer;
//genero i quattro figli/server e mi salvo i pid in un array
int index;
for (index=0 ; index<5 ; index++) {
server[index] = fork();
if (server[index] == 0)
break;
}
//verifico quale processo sono
if (index == 5) {
pause(); //aspetto un segnale da uno dei figli
}
//sono un figlio/server
else {
while(esci) {
timer.tv_sec = 1;
timer.tv_usec = 0;
if (select(list+1, &fd, NULL, NULL, &timer) <= 0) {
printf("Nessun client da servire\n");
continue;
}
if (!FD_ISSET(list, &fd))
continue;
printf("C'è un client\n");
sock = accept(list, (struct sockaddr*) &client, (socklen_t*) &client_size);
if (sock < 0)
break;
printf("Connesso con il client\n");
recv(sock, comando, 15, 0);
recv(sock, lettura, 512, 0);
if (comando[0] == 'F' && comando[1] == 'I' && comando[2] == 'N' && comando[3] == 'E' && comando[4] == '\0')
kill(getppid(), SIGALRM); //al termine dell'esecuzione uscirò
ripulisci(lettura);
//il comando è tuttomaiuscole
if (strcmp("tuttomaiuscolo", comando) == 0) {
maiuscola(lettura, scrittura);
send(sock, scrittura, 512, 0);
}
//il comando è tuttominuscole
else if (strcmp("tuttominuscolo", comando) == 0) {
minuscola(lettura, scrittura);
send(sock, scrittura, 512, 0);
}
//c'è stato un errore
else {
printf ("Error! Command not found\n");
strcpy (scrittura, "error");
send (sock, scrittura, 512, 0);
}
printf("Devo terminare!");
close(sock);
exit(0);
}
}
//termino tutto
for(index=0 ; index<5 ; index++) {
waitpid((int)server[index], NULL, 0);
}
exit(0);
}
void handler(int sig) {
signal(sig, SIG_IGN);
printf("Il server sta terminando in seguito ad una richiesta\n");
close (list);
close (sock);
exit(0);
}
void ripulisci (char* stringa) {
int index = 0;
int app;
while (stringa[index] != '\0' && index<=511) {
if (isalpha(stringa[index])!=1) {
app = index;
do {
stringa[app] = stringa[app+1];
app++;
} while (stringa[app] != '\0');
stringa[app] = '\0';
index--;
}
index++;
}
return;
}
void minuscola (char* orig, char* dest) {
int index = 0;
do {
if (orig[index] < 91)
dest[index] = toupper(orig[index]);
else
dest[index] = orig[index];
index++;
} while (orig[index] != '\0');
dest[index] = '\0';
return;
}
void maiuscola (char* orig, char* dest) {
int index = 0;
do {
if (orig[index] > 91)
dest[index] = tolower(orig[index]);
else
dest[index] = orig[index];
index++;
} while (orig[index] != '\0');
dest[index] = '\0';
return;
}
client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <time.h>
int main () {
int descrittoreSocket;
descrittoreSocket = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = htons(2770);
address.sin_addr.s_addr = INADDR_ANY;
printf ("Connessione in corso...\n");
int ris;
ris = connect(descrittoreSocket, (struct sockaddr*) &address, (socklen_t) sizeof(address));
fd_set fd;
FD_ZERO(&fd);
FD_SET(descrittoreSocket, &fd);
struct timeval timer;
timer.tv_sec = 1;
timer.tv_usec = 0;
if ((ris > -1) && select(descrittoreSocket+1, NULL, &fd, NULL, &timer) >= 0 && FD_ISSET(descrittoreSocket, &fd)) {
printf ("Connessione avvenuta...\n");
char buffer_r [512];
char buffer_w [512];
char command [15];
gets(command);
gets(buffer_r);
send(descrittoreSocket, command, 15, 0);
printf("Spedito!");
fflush(stdout);
send(descrittoreSocket, buffer_w, 512, 0);
printf("Spedito!");
fflush(stdout);
recv(descrittoreSocket, buffer_r, 512, 0);
printf("Trasferito!");
fflush(stdout);
if (strcmp("error", buffer_r) == 0)
printf ("ERROR!");
printf ("%s", buffer_r);
fflush(stdout);
} else {
printf ("Impossibile servire il client\n");
}
close (descrittoreSocket);
exit(0);
}
With syntax higligh:
server: http://pastebin.com/5Nd96JxC
client: http://pastebin.com/aSvR6qVM
Please don’t hesitate to ask for clarifications if needed.
Your server shouldn’t need to use
selectwith only one listening socket … instead it should listen for a connection on the listening socket for a client, and when there’s a connection, accept it, and then read from the socket the command given by the client. If you want to process more than one request from a client at a time, then you can spin off a separate process or thread for each accepted connection. If you want to avoid blocking behavior during the call toacceptby the listening socket, then you can always useioctlwith theFIONBIOflag on the listening socket.On the client side I also don’t see a need for
select… again, there is only one socket on the server to talk to. Simply open a connection on the server, which will block until a connection is made, and when that connection is made, you can read and write to the server.