我想实现一个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不会出现:
实际上,它不会从child中定义的SIGUSR1返回任何内容,但是你可以看到它停止了该进程(实际上你可以看到它不能再用端口49512工作,因为pidparent + 1是关联的与那个港口)。我希望我很清楚。我怎么解决呢?
答案 0 :(得分:0)
我发现它因shmat失败了......我不知道为什么,但我根据这个例子改写了代码:How to trigger SIGUSR1 and SIGUSR2? 现在它工作正常。