J'écris un programme client basé sur des sockets posix. Le programme crée plusieurs threads et va verrouiller le serveur. Mais pendant le débogage en temps gdb, le programme donne une info (erreur)
(gdb) n Program received signal SIGPIPE, Broken pipe. [Switching to Thread 0xb74c0b40 (LWP 4864)] 0xb7fdd424 in __kernel_vsyscall () (gdb)
Voici le code:
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int get_hostname_by_ip(char* h , char* ip)
{
struct hostent *he;
struct in_addr **addr_list;
int i;
if ((he = gethostbyname(h)) == NULL)
{
perror("gethostbyname");
return 1;
}
addr_list = (struct in_addr **) he->h_addr_list;
for(i = 0; addr_list[i] != NULL; i++)
{
strcpy(ip , inet_ntoa(*addr_list[i]) );
return 0;
}
return 1;
}
void client(char* h, int s)
{
int fd;
struct sockaddr_in addr;
char ch[]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
fd = socket(AF_INET, SOCK_STREAM, 0);
addr.sin_family=AF_INET;
char* ip = new char[20];
get_hostname_by_ip(h, ip);
addr.sin_addr.s_addr=inet_addr(ip);
int port = 80;
addr.sin_port=htons(port);
if(connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0)
{
perror("connect error");
return;
}
while(1)
{
if(send(fd, ch, sizeof(ch), 0) < 0)
{
perror("send");
}
}
//char buffer[1024];
//if(recv(fd, &buffer, sizeof(buffer), 0) < 0)
//{
// perror("recive");
//}
//printf("nReply from Server: %s\n", buffer);
close(fd);
}
struct info
{
char* h;
int c;
};
void* thread_entry_point(void* i)
{
info* in = (info*)i;
client(in->h, in->c);
}
int main(int argc, char** argv)
{
int s = atoi(argv[2]);
pthread_t t[s];
info in = {argv[1], s};
for(int i = 0; i < s; ++i)
{
pthread_create(&t[i], NULL, thread_entry_point, (void*)&in);
}
pthread_join(t[0], NULL);
return 0;
}
Qu'est-ce que c'est et que faire?
Le processus a reçu un SIGPIPE
. Le comportement par défaut de ce signal est de mettre fin au processus.
Un SIGPIPE
est envoyé à un processus s'il a essayé d'écrire sur un socket qui avait été arrêté pour l'écriture ou qui n'est plus connecté (plus).
Pour éviter que le programme se termine dans ce cas, vous pouvez soit
faire ignorer le processus SIGPIPE
#include <signal.h>
int main(void)
{
sigaction(SIGPIPE, &(struct sigaction){SIG_IGN}, NULL);
...
ou
installez un gestionnaire explicite pour SIGPIPE
(ne faisant généralement rien):
#include <signal.h>
void sigpipe_handler(int unused)
{
}
int main(void)
{
sigaction(SIGPIPE, &(struct sigaction){sigpipe_handler}, NULL);
...
Dans les deux cas, send*()
/write()
retournerait -1
Et définirait errno
sur EPIPE
.
Lors du débogage avec 'gdb', il est possible de désactiver manuellement SIGPIPE comme suit:
(gdb) poignée SIGPIPE nostop
Solution de contournement pour SIGPIPE, vous pouvez ignorer ce signal par ce code:
#include <signal.h>
/* Catch Signal Handler functio */
void signal_callback_handler(int signum){
printf("Caught signal SIGPIPE %d\n",signum);
}
dans votre code (principal ou global)
/* Catch Signal Handler SIGPIPE */
signal(SIGPIPE, signal_callback_handler);
Vous avez écrit sur une connexion qui a déjà été fermée par l'homologue.
J'ai en quelque sorte rencontré le même problème et cela m'a permis de SO poster. J'ai reçu des signaux SIGPIPE sporadiques provoquant des plantages de mon programme fastcgi C exécuté par nginx. J'ai essayé de signal(SIGPIPE, SIG_IGN);
sans chance, il s'est écrasé.
La raison en était que le répertoire temporaire de nginx avait un problème d'autorisation. La correction des autorisations a résolu le problème SIGPIPE. Détails ici sur la façon de réparer et plus ici .