Case '2':recv(newS,buf,sizeof(buf),0);// Таб.номер

strcpy(em[num].number,buf);

break;

Case '3':recv(newS,buf,sizeof(buf),0);// Доход

strcpy(em[num].income,buf);

break;

Case '4':recv(newS,buf,sizeof(buf),0);// Ставка налога

strcpy(em[num].tax,buf);

}

break;

case '3':

for (i=1;i<=5;i++){

buf[0]='\0';

strcat(buf,em[i].name);strcat(buf," ");

strcat(buf,em[i].number);strcat(buf," ");

strcat(buf,em[i].income);strcat(buf," ");

strcat(buf,em[i].tax);strcat(buf,"\n");

send(newS,buf,sizeof(buf),0);

}

break;

case '4':

exit(0);

}

}

}

Поскольку в параллельных серверах для динамического создания процессов используется функция fork() (см. ниже), они являются потенциальным источником проблемы не полностью завершившихся процессов (процессов, информация о которых остается в системных таблицах). В системе Linux эта проблема решается путем передачи специального сигнала родительскому процессу после завершения работы каждого дочернего процесса. Завершившийся процесс остается в виде так называемого процесса-зомби до тех пор, пока родительским процессом не будет выполнен системный вызов wait3. Для полного завершения дочернего процесса (т.е. для уничтожения процесса-зомби) в рассматриваемом примере перехватывается сигнал завершения дочернего процесса и выполняется функция обработки этого сигнала. Операционной системе дается указание, что для ведущего процесса сервера при получении каждого сигнала о завершении работы дочернего процесса (сигнал SIGCHLD) должна быть выполнена функция reaper(), в виде следующего вызова, который в нашей программе осуществляется в main:

signal (SIGCHLD, reaper);

После вызова функции signal() система автоматически вызывает функцию reaper() при получении процессом сервера каждого сигнала SIGCHLD.

Функция reaper() вызывает системную функцию wait3() для полного завершения дочернего процесса, закончившего свою работу. Функция wait3() остается заблокированной до тех пор, пока не произойдет завершение работы одного или нескольких дочерних процесса (по любой причине). Эта функция возвращает значение структуры status, которую можно проанализировать для получения дополнительной информации о завершившемся процессе. Поскольку данная программа вызывает функцию wait3() при получении сигнала SIGCHLD, вызов этой функции всегда происходит только после завершения работы дочернего процесса. Для предотвращения возникновения в сервере тупиковой ситуации в случае ошибочного вызова в программе используется параметр WNOHANG, который указывает, что функция wait3 не должна блокироваться в ожидании завершения какого-либо процесса. Вместо этого возврат управления после вызова происходит немедленно, даже если не произошел выход из какого-либо процесса.

void reaper(int sig){

int status;

while (wait3(&status,WNOHANG,(struct rusage*)0)>=0);

}

int main(){

strcpy(em[1].name,"Sergeev Sergei Sergeevich");

strcpy(em[1].number,"1");

strcpy(em[1].income,"100000");

strcpy(em[1].tax,"10");

strcpy(em[2].name,"Ivanov Ivan Ivanovich");

strcpy(em[2].number,"2");

strcpy(em[2].income,"200000");

strcpy(em[2].tax,"20");

strcpy(em[3].name,"Vladimirov Vladimir Vladimirovich");

strcpy(em[3].number,"3");

strcpy(em[3].income,"300000");

strcpy(em[3].tax,"30");

strcpy(em[4].name,"Sidorov Sidor Sidorovich ");

strcpy(em[4].number,"4");

strcpy(em[4].income,"400000");

strcpy(em[4].tax,"40");

strcpy(em[5].name,"Vasilev Vasilii Vasilievich");

strcpy(em[5].number,"5");

strcpy(em[5].income,"500000");

strcpy(em[5].tax,"50");

struct sockaddr_in local;

Int s,

NewS,

rc;

local.sin_family=AF_INET;

local.sin_port=htons(7500);

local.sin_addr.s_addr=htonl(INADDR_ANY);

s=socket(AF_INET, SOCK_STREAM,0);

rc=bind(s,(struct sockaddr *)&local, sizeof(local));

rc=listen(s,5);

(void)signal(SIGCHLD,reaper);

while(true){

newS=accept(s,NULL,NULL);

switch (fork()){

case 0:

(void)close(s);

exit(Func(newS));

default:

(void)close(newS);

}

}

return 0;

}

КЛИЕНТСКАЯ часть

#include <sys/types.h>

#include<sys/socket.h>

#include<netinet/in.h>

#include<arpa/inet.h>

#include<stdio.h>

#include <stdlib.h>

#include <string.h>

int main (){

struct sockaddr_in peer;

int s,t,t1;

int rc;

char buf[256],p,p1,b[256];;

peer.sin_family=AF_INET;

peer.sin_port=htons(7500);

peer.sin_addr.s_addr=inet_addr("127.0.0.1");

s=socket(AF_INET,SOCK_STREAM,0);

rc=connect(s,(struct sockaddr *)&peer,sizeof(peer));

while(true){

//Выбор пункта меню и отправка его серверу

puts("Choose:");

puts("\t1 - Select");

puts("\t2 - Edit");

puts("\t3 - View");

puts("\t4 - Exit");

scanf("%s",buf);

buf[1]='\0';

send(s,buf,sizeof(buf),0);

p=buf[0];

switch (p){

Case '1'://Выбрать

puts("kol-vo months (1-12) :");scanf("%s",buf);

send(s,buf,sizeof(buf),0);

puts("Symbol: ");scanf("%s",buf);

send(s,buf,sizeof(buf),0);

printf("Sum of taxes: ");

recv(s,buf,sizeof(buf),0);

for (t=0;buf[t+3];t++) printf("%c",buf[t]);

printf(".");

for (t1=t;buf[t1];t1++) printf("%c",buf[t1]);

printf("\n");

break;

Case '2'://Подредактировать

puts("What number (1-5) to edit");

scanf("%s",buf);//Какой номер будем редактировать

send(s,buf,sizeof(buf),0);

puts("What field (1-4) to edit");

puts("\t1 - Name");

puts("\t2 - Number");

puts("\t3 - Income");

puts("\t4 - Tax");

scanf("%s",buf);

send(s,buf,sizeof(buf),0);

p1=buf[0];

buf[0]='\0';

switch(p1){ //Введите новые поля

case '1':printf("Name: ");

fflush(stdin);fflush(stdout);

scanf("%s",b);strcat(buf,b);strcat(buf," ");

scanf("%s",b);strcat(buf,b);strcat(buf," ");

scanf("%s",b);strcat(buf,b);strcat(buf,"\0");

//puts(buf);

send(s,buf,sizeof(buf),0);

break;

case '2':fflush(stdin);fflush(stdout);

printf("Tab Number: ");scanf("%s",buf);

send(s,buf,sizeof(buf),0);

break;

case '3':fflush(stdin);fflush(stdout);

printf("Income per month: ");scanf("%s",buf);

send(s,buf,sizeof(buf),0);

break;

case '4':fflush(stdin);fflush(stdout);

printf("Tax rate (%) per month: ");scanf("%s",buf);

send(s,buf,sizeof(buf),0);

}

break;

Наши рекомендации