Recv(newS,buf,sizeof(buf),0);// Имя

Лабораторная работа №4

Создание клиент-серверных приложений с установлением логического соединения (TCP/IP), используя алгоритм параллельной обработки запросов (отдельный процесс для обработки каждого запроса)

Цель работы – изучить методы создания клиент-серверных приложений, используя однопотоковые параллельные серверы (TCP).

В первой лабораторной работе были описаны особенности создания транспортного протокола с установлением логического соединения в последовательном сервере и показан пример его применения. В настоящей лабораторной работе приведен пример параллельного сервера, в котором используется транспортный протокол с установлением логического соединения. Этот сервер при обеспечении параллельного формирования ответов на запросы опирается на поддержку параллельного выполнения процессов операционной системой. Системный администратор предусматривает автоматический запуск ведущего серверного процесса во время начальной загрузки системы. Ведущий сервер функционирует неопределенно долгое время, ожидая поступления новых запросов на установление соединения от клиентов. Ведущий поток создает новый ведомый поток для обработки запросов каждого нового соединения и предоставляет каждому ведомому потоку возможность взять на себя весь обмен данными с клиентом. В настоящей лабораторной работе рассматривается реализация, в которой используется несколько однопотоковых процессов.

Последовательная реализация сервера, может оказаться неудовлетворительной, поскольку клиенты будут вынуждены ждать завершения обработки всех предыдущих запросов на установление соединения. Если клиент решит передать большие объемы данных (например, несколько мегабайт), последовательный сервер отложит обслуживание всех других клиентов до тех пор, пока не выполнит этот запрос.

Параллельная реализация сервера дает возможность обойтись без продолжительных задержек, так как не позволяет одному клиенту захватить все ресурсы. Вместо этого параллельный сервер поддерживает обмен данными сразу с несколькими клиентами для того, чтобы их запросы выполнялись одновременно. Поэтому, с точки зрения клиента, параллельный сервер обеспечивает лучшее наблюдаемое время отклика по сравнению с последовательным сервером.

Recv(newS,buf,sizeof(buf),0);// Имя - student2.ru

Рис. 4.1. Схема организации процессов параллельного сервера с установлением логического соединения, в котором используются однопотоковые процессы

На рис.4.1. показана схема организации процессов параллельного сервера с установлением логического соединения, в котором используются однопотоковые процессы. Как показано на этом рисунке, ведущий процесс непосредственно не взаимодействует с клиентами. По существу, в его задачу входит просто ожидание поступления очередного запроса на установление соединения через общепринятый порт. После поступления такого запроса система возвращает новый дескриптор сокета, предназначенный для использования с этим соединением. Ведущий процесс создает ведомый процесс для обслуживания соединения и предоставляет возможность ведомому процессу работать параллельно с ним. В любое время в сервере функционирует один ведущий процесс, а число ведомых процессов может составлять от нуля и более. Ведущий процесс сервера принимает каждый входящий запрос на установление соединения и создает ведомый процесс для его обслуживания.

Для получения очередного запроса на установление соединения из общепринятого порта используется блокирующий вызов функции accept, что позволяет предотвратить бесполезное расходование ресурсов процессора во время ожидания очередных запросов на установление соединения в ведущем процессе сервера. Поэтому, в отличие от последовательного сервера, ведущий процесс сервера в параллельном сервере основную часть времени проводит в состоянии, заблокированном в вызове функции accept. После поступления запроса на установление соединения выполняется возврат управления функцией accept, а ведущий процесс получает возможность продолжить выполнение. Ведущий процесс создает ведомый процесс для обработки запроса и снова вызывает функцию accept. В этом вызове ведущий процесс в очередной раз блокируется до поступления еще одного запроса на установление соединения.

Методические указания

Рассмотрим все описанное выше на конкретном примере:

Осуществить взаимодействие клиента и сервера на основе протокола TCP. Реализовать параллельное соединение с использованием одного потока. На сервере хранится список сотрудников фирмы. Каждая запись списка содержит следующую информацию о сотрудниках

- Ф. И. О. сотрудника;

- табельный номер;

- доход в месяц;

- ставка налогов, отчисляемых в бюджет.

Таких записей должно быть не менее 5.

Клиент посылает на сервер количество месяцев и символ алфавита (первая буква фамилии сотрудника) и получает назад общую сумму отчислений налогов в бюджет, уплачиваемые сотрудниками в течение этих месяцев, фамилии которых начинаются с этого символа. Предусмотреть возможность редактирования записей списка клиентом.

Решение этой задачи подразумевает использование компилятора языка С++ gcc, поставляемого вместе с эмулятором операционной системы Unix – Cygwin (см. приложение 1).

Для реализации поставленной задачи, как и ранее, создадим два проекта, для отладки и компиляции которых используем оболочку Cygwin.

СЕРВЕРНАЯ часть.

// Подключение необходимых библиотек для работы с пакетом Cygwin

#include <sys/types.h>

#include<sys/socket.h>

#include<sys/signal.h>

#include<sys/wait.h>

#include<sys/resource.h>

#include<netinet/in.h>

#include <string.h>

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

struct Employee{

char name[35];

char number[10];

char income[10];

char tax[4];

} em[5];

// процедура для обслуживания соединения

int Func(int newS){

long int i,num,t, mon, doh, nal;

float sum;

int m;

char p,p1,s;

char buf[256],b[256];

while (true){

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

p=buf[0];

switch(p){

case '1':

buf[0]='\0';

sum=0;

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

mon=atoi(buf);

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

s=buf[0];

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

if (em[i].name[0]==s){

nal=atoi(em[i].tax);

doh=atoi(em[i].income);

printf("mon %d\n",mon);

sum=sum+(nal*doh*mon)/100.0;

}

int* decpt,*sgn;

printf("%f\n",sum);

strcpy(buf,fcvt(sum,3,decpt,sgn));

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

puts(buf);

break;

case '2':

recv(newS,buf,sizeof(buf),0);// Номер

num=atoi(buf);

printf("%d\n",num);

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

p1=buf[0];

switch(p1){

case '1':

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;

Case '4'://Выход

exit(0);

}

}

}

Как показано в этом примере, вызовы функций, обеспечивающих параллельную работу, занимают лишь небольшую часть кода. Ведущий процесс сервера начинает свое выполнение в главной процедуре.

При каждом проходе по циклу ведущий сервер вызывает функцию accept() для перехода в состояние ожидания запроса на установление соединения от клиента. Как и в последовательном сервере, этот вызов блокируется до поступления запроса. После получения программным обеспечением базового протокола ТСР запроса на установление соединения операционная система создает сокет для нового соединения и вызов функции accept() возвращает дескриптор этого сокета.

После возврата управления из функции accept() ведущий процесс сервера создает ведомый процесс для обслуживания соединения. Для этого ведущий процесс вызывает функцию fork(), чтобы разделиться на два процесса. Поток во вновь созданном дочернем процессе вначале закрывает сокет ведущего процесса, а затем вызывает функцию Func() для обслуживания соединения. Поток в родительском процессе закрывает сокет, который был создан для обслуживания нового соединения, и продолжает выполнение бесконечного цикла. При следующем проходе по циклу ведущий процесс после вызова функции accept() снова переходит в состояние ожидания очередных запросов на установление соединения. Следует отметить, что и первоначальный, и новые процессы имеют доступ к открытым сокетам после вызова функции fork() и, что они оба должны закрыть один из этих сокетов, после чего система освобождает связанный с ним ресурс. Поэтому этот сокет закрывается только в ведущем процессе после вызова функции close() потоком ведущего процесса для закрытия сокета нового соединения. Аналогичным образом, когда поток в ведомом процессе вызывает функцию close() для закрытия сокета ведущего процесса, этот сокет закрывается только в ведомом процессе. Ведомый процесс продолжает получать доступ к сокету нового соединения до тех пор, пока не завершит свою работу, а ведущий сервер продолжает иметь доступ к сокету, который соответствует общепринятому порту.

После закрытия сокета ведущего процесса ведомый процесс вызывает процедуру Func(). После возврата управления процедурой Func() ведомый процесс использует возвращенное значение в качестве параметра вызова функции exit. Система Linux интерпретирует вызов функции exit как требование завершить процесс и использует параметр вызова этой функции как код завершения процесса. В соответствии с общепринятым соглашением, в процессе для обозначения нормального завершения используется код завершения нуль. После прекращения работы ведомого процесса операционная система автоматически закрывает все его открытие дескрипторы, в том числе дескриптор соединения ТСР.

Контрольные вопросы

1. По какой причине последовательная реализация сервера, может оказаться неудовлетворительной?

2. Какие преимущества предоставляет параллельная реализация сервера?

3. Какие основные задачи выполняет ведущий процесс?

4. Для чего используется блокирующий вызов функции accept()?

5. Когда и для чего вызывается функция fork()?

6. Каким образом решается проблема не полностью завершившихся процессов (процессов, информация о которых остается в системных таблицах)?

7. Какой код используется в процессе для обозначения нормального завершения?

Варианты индивидуального задания

1. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список о студентов. Каждая запись списка содержит следующую информацию о студенте

- Ф.И.О. студента;

- номер группы;

- размер стипендии;

- оценки по N предметам.

Таких записей должно быть не менее 5.

Клиент вводит с клавиатуры букву алфавита, по которой он хотел бы посмотреть информацию о студентах и посылает ее на сервер. Назад он получает список только тех студентов, фамилии которых начинаются на эту букву.

2. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список о студентов. Каждая запись списка содержит следующую информацию о студенте

- Ф.И.О. студента;

- номер группы;

- размер стипендии;

- оценки по N предметам.

Таких записей должно быть не менее 5.

Клиент посылает на сервер средний балл студента, по которому он хочет получить информацию о студентах. Назад он получает список только тех студентов, средний балл которых больше заданного.

3. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список о студентов. Каждая запись списка содержит следующую информацию о студенте

- Ф.И.О. студента;

- номер группы;

- размер стипендии;

- оценки по N предметам.

Таких записей должно быть не менее 5.

По запросу клиента он получает от сервера список только тех студентов, которые не имеют оценки 3.

4. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список сотрудников фирмы. Каждая запись списка содержит следующую информацию о сотрудниках

- Ф.И.О. сотрудника;

- табельный номер;

- количество отработанных часов за месяц;

- почасовой тариф.

Таких записей должно быть не менее 5.

Клиент посылает на сервер величину заработной платы, по которой он хочет получить информацию о сотрудниках. Назад он получает список только тех сотрудников, заработная плата которых меньше указанной.

5. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится информация (список) о комплектующих деталях. Каждая запись списка содержит следующую информацию о комплектующем

- завод-поставщик;

- стоимость;

- дата поставки;

Таких записей должно быть не менее 7.

Клиент посылает на сервер дату поставки. Назад он получает список комплектующих поставленных именно на эту дату и стоимость каждого возвращаемого комплектующего должна превосходить минимальную во всем списке.

6. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список автобусных рейсов. Каждая запись списка содержит следующую информацию о рейсе

- номер рейса;

- тип автобуса;

- цена билета;

- пункт назначения.

Таких записей должно быть не менее 5.

Клиент посылает на сервер пункт назначения. Назад он получает список рейсов, позволяющих добраться до заданного пункта.

7. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список игроков. Каждая запись списка содержит следующую информацию об игроках

- Ф. И. О. игрока;

- игровой номер;

- возраст;

- рост;

- вес.

Таких записей должно быть не менее 5.

Клиент посылает на сервер запрос и получает информацию о самом молодом игроке.

8. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список разговоров на междугородней АТС. Каждая запись списка содержит следующую информацию о разговорах

- дату разговора;

- код и название города;

- продолжительность разговора;

- тариф;

- номер телефона в этом городе;

- номер телефона абонента.

Таких записей должно быть не менее 5.

Клиент посылает на сервер название города. Назад он получает суммарное время разговора с указанным городом.

9. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список товаров, имеющихся на складе. Каждая запись списка содержит следующую информацию о товарах

- страна-изготовитель;

- фирма-изготовитель;

- наименование товара;

- количество единиц товара.

Таких записей должно быть не менее 5.

Клиент посылает на сервер страну-изготовитель. Назад он получает товары и их данные для указанной страны.

10. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список книг, хранящихся в библиотеке. Каждая запись списка содержит следующую информацию о книгах

- регистрационный номер книги,

- автор;

- название;

- год издания;

- издательство;

- количество страниц.

Таких записей должно быть не менее 5.

Клиент посылает на сервер фамилию интересующего его автора. Назад он получает список книг указанного автора.

11. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список деталей. Каждая запись списка содержит следующую информацию о деталях

- наименование детали;

- количество деталей;

- номер цеха, где они изготовлены.

Таких записей должно быть не менее 7.

Клиент посылает на сервер наименование детали. Назад он получает общее количество изделий указанного наименования.

12. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список товаров, имеющихся на складе. Каждая запись списка содержит следующую информацию о товарах

- страна-изготовитель;

- фирма-изготовитель;

- наименование товара;

- количество единиц товара.

Таких записей должно быть не менее 5.

Клиент посылает на сервер наименование товара. Назад он получает количество единиц этого товара.

13. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится каталог туристических предложений. Каждая запись каталога содержит:

- название тура

- стоимость

- продолжительность

- вид транспорта

Таких записей должно быть не менее 5.

Клиент посылает на сервер предполагаемую стоимость тура. Назад он получает названия тех туров, стоимость которых не выше.

14. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится список преподавателей. Каждая запись списка содержит:

- Ф.И.О.

- ученая степень

- стаж работы

- предмет

Клиент посылает на сервер название предмета. Назад он получает Ф.И.О. тех преподавателей этого предмета, стаж работы которых не менее 5 лет.

15. Осуществить взаимодействие клиента и сервера на основе протокола TCP/IP. Реализовать параллельное соединение с использованием отдельного процесса для обработки каждого запроса. На сервере хранится информация об участниках соревнований по спортивным танцам. Она включает:

- название танцевальной пары

- город

- оценка жюри

- оценка зрителей

- возрастная группа

Клиент посылает на сервер возраст участников. Назад он получает название той танцевальной пары, суммарная оценка которой в данной возрастной группе максимальна.

Лабораторная работа №4

Создание клиент-серверных приложений с установлением логического соединения (TCP/IP), используя алгоритм параллельной обработки запросов (отдельный процесс для обработки каждого запроса)

Цель работы – изучить методы создания клиент-серверных приложений, используя однопотоковые параллельные серверы (TCP).

В первой лабораторной работе были описаны особенности создания транспортного протокола с установлением логического соединения в последовательном сервере и показан пример его применения. В настоящей лабораторной работе приведен пример параллельного сервера, в котором используется транспортный протокол с установлением логического соединения. Этот сервер при обеспечении параллельного формирования ответов на запросы опирается на поддержку параллельного выполнения процессов операционной системой. Системный администратор предусматривает автоматический запуск ведущего серверного процесса во время начальной загрузки системы. Ведущий сервер функционирует неопределенно долгое время, ожидая поступления новых запросов на установление соединения от клиентов. Ведущий поток создает новый ведомый поток для обработки запросов каждого нового соединения и предоставляет каждому ведомому потоку возможность взять на себя весь обмен данными с клиентом. В настоящей лабораторной работе рассматривается реализация, в которой используется несколько однопотоковых процессов.

Последовательная реализация сервера, может оказаться неудовлетворительной, поскольку клиенты будут вынуждены ждать завершения обработки всех предыдущих запросов на установление соединения. Если клиент решит передать большие объемы данных (например, несколько мегабайт), последовательный сервер отложит обслуживание всех других клиентов до тех пор, пока не выполнит этот запрос.

Параллельная реализация сервера дает возможность обойтись без продолжительных задержек, так как не позволяет одному клиенту захватить все ресурсы. Вместо этого параллельный сервер поддерживает обмен данными сразу с несколькими клиентами для того, чтобы их запросы выполнялись одновременно. Поэтому, с точки зрения клиента, параллельный сервер обеспечивает лучшее наблюдаемое время отклика по сравнению с последовательным сервером.

Recv(newS,buf,sizeof(buf),0);// Имя - student2.ru

Рис. 4.1. Схема организации процессов параллельного сервера с установлением логического соединения, в котором используются однопотоковые процессы

На рис.4.1. показана схема организации процессов параллельного сервера с установлением логического соединения, в котором используются однопотоковые процессы. Как показано на этом рисунке, ведущий процесс непосредственно не взаимодействует с клиентами. По существу, в его задачу входит просто ожидание поступления очередного запроса на установление соединения через общепринятый порт. После поступления такого запроса система возвращает новый дескриптор сокета, предназначенный для использования с этим соединением. Ведущий процесс создает ведомый процесс для обслуживания соединения и предоставляет возможность ведомому процессу работать параллельно с ним. В любое время в сервере функционирует один ведущий процесс, а число ведомых процессов может составлять от нуля и более. Ведущий процесс сервера принимает каждый входящий запрос на установление соединения и создает ведомый процесс для его обслуживания.

Для получения очередного запроса на установление соединения из общепринятого порта используется блокирующий вызов функции accept, что позволяет предотвратить бесполезное расходование ресурсов процессора во время ожидания очередных запросов на установление соединения в ведущем процессе сервера. Поэтому, в отличие от последовательного сервера, ведущий процесс сервера в параллельном сервере основную часть времени проводит в состоянии, заблокированном в вызове функции accept. После поступления запроса на установление соединения выполняется возврат управления функцией accept, а ведущий процесс получает возможность продолжить выполнение. Ведущий процесс создает ведомый процесс для обработки запроса и снова вызывает функцию accept. В этом вызове ведущий процесс в очередной раз блокируется до поступления еще одного запроса на установление соединения.

Методические указания

Рассмотрим все описанное выше на конкретном примере:

Осуществить взаимодействие клиента и сервера на основе протокола TCP. Реализовать параллельное соединение с использованием одного потока. На сервере хранится список сотрудников фирмы. Каждая запись списка содержит следующую информацию о сотрудниках

- Ф. И. О. сотрудника;

- табельный номер;

- доход в месяц;

- ставка налогов, отчисляемых в бюджет.

Таких записей должно быть не менее 5.

Клиент посылает на сервер количество месяцев и символ алфавита (первая буква фамилии сотрудника) и получает назад общую сумму отчислений налогов в бюджет, уплачиваемые сотрудниками в течение этих месяцев, фамилии которых начинаются с этого символа. Предусмотреть возможность редактирования записей списка клиентом.

Решение этой задачи подразумевает использование компилятора языка С++ gcc, поставляемого вместе с эмулятором операционной системы Unix – Cygwin (см. приложение 1).

Для реализации поставленной задачи, как и ранее, создадим два проекта, для отладки и компиляции которых используем оболочку Cygwin.

СЕРВЕРНАЯ часть.

// Подключение необходимых библиотек для работы с пакетом Cygwin

#include <sys/types.h>

#include<sys/socket.h>

#include<sys/signal.h>

#include<sys/wait.h>

#include<sys/resource.h>

#include<netinet/in.h>

#include <string.h>

#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

struct Employee{

char name[35];

char number[10];

char income[10];

char tax[4];

} em[5];

// процедура для обслуживания соединения

int Func(int newS){

long int i,num,t, mon, doh, nal;

float sum;

int m;

char p,p1,s;

char buf[256],b[256];

while (true){

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

p=buf[0];

switch(p){

case '1':

buf[0]='\0';

sum=0;

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

mon=atoi(buf);

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

s=buf[0];

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

if (em[i].name[0]==s){

nal=atoi(em[i].tax);

doh=atoi(em[i].income);

printf("mon %d\n",mon);

sum=sum+(nal*doh*mon)/100.0;

}

int* decpt,*sgn;

printf("%f\n",sum);

strcpy(buf,fcvt(sum,3,decpt,sgn));

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

puts(buf);

break;

case '2':

recv(newS,buf,sizeof(buf),0);// Номер

num=atoi(buf);

printf("%d\n",num);

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

p1=buf[0];

switch(p1){

case '1':

recv(newS,buf,sizeof(buf),0);// Имя

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

break;

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