c中父母和孩子之间的sigusr1

时间:2017-09-17 11:27:08

标签: c multithreading udp signals fork

我想实现一个UDP服务器,该服务器使用三个线程(三个端口)来执行相同的操作。在一个线程中,每个线程都有一个父节点和一个子节点:父节点等待来自客户端的请求,子节点增加一个变量。当父接收请求时,它会向孩子的pid发送一个信号(SIGUSR1)(尝试,我使用parentpid + 1)。子类默认增加变量,由SIGUSR1写一些东西(例如:“我在sigurs1”中),但实际上我也希望将变量的状态发送到主线程。 Howevere,这是代码:

/**
@defgroup Group4 UDP Client and Server

@brief UDP/IPv4 Client and Server
@{
*/
/**
@file 	UDPServer.c
@author Catiuscia Melle

@brief 	Presentazione di un UDP Echo Server IPv4.

Il server, in un ciclo infinito:
- riceve un messaggio 
- lo re-invia in echo.
*/


#include "Header.h"

//@@@ PRIMA DI TUTTO INCLUDIAMO LA LIBRERIA PER I SEGNALI
#include <signal.h>


void *thread_function(void *arg);
int stock = 0;

//@@@ Il sigset_t viene utilizzato per rappresentare un signal set
sigset_t	mask;

int main(){
	
	printf("\tIPv4 UDP Server app\n");
	
	int port1 = PORT, port2 = PORT2, port3 = PORT3;
	
	//INITIALITE THREAD AND VARIABLES FOR THREAD
	int thres; //response of the thread
    pthread_t a_thread, a_thread2, a_thread3;
    void *thread_result;
    
    //CREATE THREAD 1
    thres = pthread_create(&a_thread, NULL, thread_function, &port1);
    if (thres != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
    
    //CREATE THREAD 2
    thres = pthread_create(&a_thread2, NULL, thread_function, &port2);
    if (thres != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
		
	//CREATE THREAD 3
    thres = pthread_create(&a_thread3, NULL, thread_function, &port3);
    if (thres != 0) {
        perror("Thread creation failed");
        exit(EXIT_FAILURE);
    }
	
	thres = pthread_join(a_thread, &thread_result);
  	if (thres != 0) {
    	perror("Thread join failed");
    	exit(EXIT_FAILURE);
    }
    
    thres = pthread_join(a_thread2, &thread_result);
  	if (thres != 0) {
    	perror("Thread join failed");
    	exit(EXIT_FAILURE);
    }
        			
    thres = pthread_join(a_thread3, &thread_result);
  	if (thres != 0) {
    	perror("Thread join failed");
    	exit(EXIT_FAILURE);
    }
		
	
	
return 0;
}

void *thread_function(void *arg) {

	pid_t	pid;
	int parentpid = getpid();
	
	printf("Il pid della thread vale %d\n",parentpid);
	
	int port = *((int *) arg);
	
//@@@ Nella variabile signo salverò il numero di segnale che mi restituisce la wait
	int err, signo;
	
	printf("Porta %d\n",port);
	

	printf("ENTER TO THREAD\n");
	

	int res = 0; //valore di ritorno delle APIs

	/*
	socket: servirà per la comunicazione col server
	*/
	int sockfd = 0;
	
	/*
	open socket di tipo datagram
	*/
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if (sockfd == -1)
	{
		perror("socket error: ");
		return FAILURE;
	}
	
	/*
	indirizzo IPv4 del server, senza hostname resolution
	*/
	struct sockaddr_in server;
	socklen_t len = sizeof(server);
	
	memset(&server, 0, sizeof(server)); //azzero la struttura dati
	server.sin_family = AF_INET; //specifico l'Address Family IPv4
	
	/*
	Specifico l'indirizzo del server: qualsiasi interfaccia
	*/
	server.sin_addr.s_addr = htonl(INADDR_ANY);
		
	/*
	Specifico la well-known port
	*/
	server.sin_port = htons(port);
	
	//setto l'indirizzo well-known del socket
	res = bind(sockfd, (struct sockaddr *)&server, len);
	if (res == -1)
	{
		perror("Bind error: ");
		close(sockfd);
		exit(1);
	}//fi
	
		
	ssize_t n = 0;
	char buffer[BUFSIZE];
	
	struct sockaddr_in client;
	char address[INET_ADDRSTRLEN] = "";
	
	int quit = 0;
	
	if ((pid = fork()) < 0) {
		printf("Fork error<n");
	} else if (pid == 0) {		/* child */
		printf("child dal pid %d\n",getpid());
		
		while(1){
			
			
			
			        //@@@ La sigwait non fa che attendere l'arrivo di un segnale
        	err = sigwait(&mask, &signo);
	
		
			//@@@ Una volta terminata la sigwait, ossia quando ha ricevuto un segnale
			//(se no è successo un errore), possiamo switchare il segnale arrivato, che
			//è salvato in signo
			switch (signo) {
		
			//@@@ Ora gestisco, se gli ho mandato un SIGUSR1, ossia un flag che, arrivato 
			//a destinazione indica di eseguire quel segnale che il processo che lo riceve
			//lo implementa come vuole. Si sa che si deve eseguire quel segnale, di libera
			//interpretazione
			case SIGUSR1:
				printf("Sigusr1\n");
				printf("Stock vale %d\n",stock);
				break;
        
     	   //@@@ In caso gli mandassi SIGINT, valuta sempre se ci sono errori e poi esci
    	    case SIGINT:
   	    		printf("Sigint\n");
			//@@@ Di default comunque, controlla se ci sono errori e poi esci
			default:
				stock++;
				printf("Sto producendo %d dalla porta %d\n",stock, port);
				sleep(2);
			}
			
			
			
			
			
			
		}
	} else {
		printf("parent dal pid %d\n",getpid());				/* parent */
		
		while (!quit)
	{
		printf("Main thread entrato nel ciclo\n");
		n = recvfrom(sockfd, buffer, BUFSIZE-1, 0, (struct sockaddr *)&client, &len);
		
		printf("Mando segnali");
		 //@@@ Inizializza il segnale settato set a escludere tutti i segnali definiti
    	sigemptyset(&mask);
    	//@@@ Aggiunge il segnale signum al segnale settato set. Con sigaddset modifichiamo
    	//set, ma non blocchiamo o sblocchiamo alcun segnale!
    	//Mettiamoli quindi SIGURS1
		sigaddset(&mask, SIGUSR1);
		//@@@ E anche SIGINT
		sigaddset(&mask, SIGINT);
		//@@@ pthread_sigmask esamina e cambia segnali bloccati. Con SIG_BLOCK il set
		//risultante è l'unione del set corrente e il set di segnale indicato da set
		if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0)
		{
        	fprintf(stderr, "thread mask failed\n");
    		exit(EXIT_FAILURE);
    	}
    	
    	kill(parentpid+1,SIGUSR1);
    	
    	printf("Segnale inviato al pid %d\n",(parentpid+1));
		
		if (n == -1)
		{
			perror("recvfrom() error: ");
			continue;
// 			close(sockfd);
// 			return FAILURE;
		}

	
	}//wend
		
	printf("Stockmann %d\n",stock);
	
	//qui non ci arrivo mai...	
	close(sockfd);
	
	}

	
	
		
			  
			
return NULL;	
}


/** @} */

这是Header.h(但没有必要看到它)

/**
@addtogroup Group11
@{
*/
/**
@file 	Header.h
@author Catiuscia Melle

@brief 	Header comune al client e server dell'esempio

L'header definisce costanti comuni al client e server.
*/

#ifndef __HEADER_H__
#define __HEADER_H__

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h> //resolver related functions

#include <sys/types.h> //necessario su Mac
#include <stdlib.h>

#include <ctype.h> //toupper()
#include <stdbool.h>

//THIS FOR RAND FUNCTION
#include <stdlib.h>
#include <time.h>

//THIS FOR THREADS
#include <pthread.h>

#define PORTNUMBER 		49152 		/**< UDP listening port, decimal */
#define PORT 		49152 		/**< UDP listening port, decimal */

#define PORT2 		49153 		/**< UDP listening port, decimal */
#define PORT3 		49154 		/**< UDP listening port, decimal */

#define SERVICEPORT 	"49152" 	/**< UDP listening port, name */
#define PORT_STRLEN 6 /**< lunghezza di una stringa rappresentativa di un indirizzo di trasporto */

#define BACKLOG 10 	/**< dimensione della coda di connessioni */

#define SIZE 15 /**< dimensione della coda di connessioni concorrenti gestite dal server */

#define BUFSIZE 512 /**< dimensione del buffer di messaggio */

#define FAILURE 3 	/**< definizione del valore di errore di ritorno del processo in caso di errori delle Sockets API */

#define INVALID 5 	/**< se i due processi non sono avviati col giusto numero di parametri */

#define ERROR 1 /**<  valore di errore */

#define INSUCCESS -1 /**< valore di ritorno non valido */

#define SEMAPHORE_NAME "gbrunetta317"

#endif /* __HEADER_H__ */

/** @} */

问题是,当我向客户端发送内容时,案例中的值:Sigurs1不会出现:

Problem

实际上,它不会从child中定义的SIGUSR1返回任何内容,但是你可以看到它停止了该进程(实际上你可以看到它不能再用端口49512工作,因为pidparent + 1是关联的与那个港口)。我希望我很清楚。我怎么解决呢?

1 个答案:

答案 0 :(得分:0)

我发现它因shmat失败了......我不知道为什么,但我根据这个例子改写了代码:How to trigger SIGUSR1 and SIGUSR2? 现在它工作正常。