marmellate Server a dopo la chiamata Reaper
Domanda
Stavo lavorando con un server TCP e qualcosa di strano ultra avvicinò.
Quando mi collego con un cliente, everythings va bene.
Quando due o più client si connette, il traffico è ancora bene.
Ma quando uno dei clienti si disconnette, le marmellate server giusto dopo la chiamata Reaper. È situata a lì in attesa.
ho scoperto questo quando ho staccato 1 cliente su 2 e cercato di riconnessione. Il client di riconnessione non visualizza alcun messaggio di errore a tutti, senza intoppi. I pacchetti possono essere inviati al server, ma si accumula all'interno del server.
Il server sugli altri si blocca mano là, in attesa di un client specifico per disconnettersi. Se quel client si disconnette, il server riprenderà la funzione, l'esecuzione di tutte le richieste che sono state accatastati all'interno di esso.
Di seguito è riportato il codice barebone che ho usato per la struttura del server.
Questo codice dimostra anche il problema di cui sopra.
Qualcuno può per favore, per favore, si prega di indicare dove è stato fatto l'errore?
void reaper(int sig)
{
int status;
while (waitpid(-1, &status, WNOHANG) >= 0)
/* empty */;
}
int errexit(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(1);
}
int errno;
unsigned short portbase = 0; /* port base, for non-root servers */
int passivesock(const char *service, const char *transport, int qlen)
{
struct servent *pse; /* pointer to service information entry */
struct protoent *ppe; /* pointer to protocol information entry*/
struct sockaddr_in sin; /* an Internet endpoint address */
int s, type; /* socket descriptor and socket type */
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
/* Map service name to port number */
if ( pse = getservbyname(service, transport) )
sin.sin_port = htons(ntohs((unsigned short)pse->s_port)
+ portbase);
else if ((sin.sin_port=htons((unsigned short)atoi(service))) == 0)
errexit("can't get \"%s\" service entry\n", service);
/* Map protocol name to protocol number */
if ( (ppe = getprotobyname(transport)) == 0)
errexit("can't get \"%s\" protocol entry\n", transport);
/* Use protocol to choose a socket type */
if (strcmp(transport, "udp") == 0)
type = SOCK_DGRAM;
else
type = SOCK_STREAM;
/* Allocate a socket */
s = socket(PF_INET, type, ppe->p_proto);
if (s < 0)
errexit("can't create socket: %s\n", strerror(s));
/* Bind the socket */
if (errno=bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
errexit("can't bind to %s port: %s\n", service,
strerror(errno));
if (type == SOCK_STREAM && listen(s, qlen) < 0)
errexit("can't listen on %s port: %s\n", service,
strerror(type));
return s;
}
int passiveTCP(const char *service, int qlen)
{
return passivesock(service, "tcp", qlen);
}
#define QLEN 32 /* maximum connection queue length */
#define BUFSIZE 4096
int TCPechod(int fd);
int main(int argc, char *argv[])
{
char *service; /* service name or port number */
struct sockaddr_in fsin; /* the address of a client */
unsigned int alen; /* length of client's address */
int msock; /* master server socket */
int ssock; /* slave server socket */
if (argc !=2)
errexit("usage: %s port\n", argv[0]);
service = argv[1];
msock = passiveTCP(service, QLEN);
(void) signal(SIGCHLD, reaper);
while (1) {
alen = sizeof(fsin);
ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
if (ssock < 0) {
if (errno == EINTR)
continue;
errexit("accept: %s\n", strerror(ssock));
}
printf("Accept connection %d from %s:%d\n", ssock, inet_ntoa(fsin.sin_addr), (int)ntohs(fsin.sin_port));
switch (fork()){
case 0:
(void) close(msock);
TCPechod(ssock);
close(ssock);
exit(0);
default:
close(ssock);
break;
case -1:
errexit("fork: %s\n", strerror(errno));
}
}
}
int TCPechod(int fd)
{
char buf[BUFSIZE];
int cc;
while (cc = read(fd, buf, sizeof(buf))) {
if (cc < 0)
errexit("echo read: %s\n", strerror(cc));
if (errno=write(fd, buf, cc) < 0)
errexit("echo write: %s\n", strerror(errno));
}
return 0;
}
Tutti i testa a testa sarebbe notevolmente apprezzato.
Vi ringrazio in anticipo.
Soluzione
Il problema è come si sta chiamando waitpid, perché si sta lasciare solo il tempo quando si è verificato un errore (ritorno waitpid <0 in caso di errore). Quando si chiama waitpid con la bandiera WNOHANG, si restituisce 0 se non v'è alcun processo figlio terminato (veramente cambiamento di stato: fermato, ripreso o terminato). Prova questo Correzione:
void reaper(int sig)
{
int status;
pid_t pid;
while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
printf("Proces PID: %d Hash Finished With Status: %d", pid, status);
if (0 == pid) printf("No More Process Waiting");
if (pid < 0) printf("An Error Ocurred");
}
Se si desidera utilizzare la funzione di attendere mietitore deve essere qualcosa del tipo:
void reaper(int sig)
{
int status;
pid_t pid;
pid = wait(&status); // Wait suspend the execution of the current process.
if (pid > 0) printf("Proces PID: %d Hash Finished With Status: %d", pid, status);
if (pid < 0) printf("An Error Ocurred");
}
Per ulteriori informazioni su wait (2) vai a: http://linux.die.net / uomo / 2 / wait
Altri suggerimenti
mi sono imbattuto in questo problema pure.
La funzione "Reaper" con il test >=0
è in esempi in tutto il luogo, ma questo può finire per essere un ciclo infinito in quanto anche una volta che si pulisce il bambino che ti terrà non loop fino a quando non ci sono più, ma fino a quando si ottiene un errore di qualche tipo.
Ci sono versioni di Perl di questo codice là fuori che di solito è "fisso" usando >0
invece di >=0
, ma si consiglia di utilizzare la logica come mostrato qui dove si esplicitamente di prova per i casi di interesse.