SOISK - SYSTEMY OPERACYJNE I SIECI KOMPUTEROWE
Tomasz Puchała

LAB 4

Instrukcja Laboratoryjna 4

Serwer współbieżny - instrukcja fork.

 

1) Wstęp teoretyczny

Celem ćwiczenia jest wykonanie współbieżnej aplikacji serwera (opartego na funkcji fork())

Wykorzystującego protokół, TCP. Po nawiązaniu połączenia przez aplikację klienta, zostaje utworzony

Proces potomny, który wykonuje określoną operację na odebranych danych.

Działanie serwera polega na pobraniu danych od klienta → wykonaniu operacji na danych klienta, oraz wysłanie rezultatu działania (taki algorytm rozwiązaliśmy poprzednio), teraz każda próba połączenia przez klienta (w tym samym czasie) powoduje utworzenie nowego procesu obsługującego zapytanie.

Aby zrealizować zadanie niniejszej instrukcji, należy wykorzystać programy iteracyjne z poprzednich

Zajęć -> dokonać modyfikacji aplikacji serwera tak, aby działał współbieżnie!!!

Aby zrealizować zadania niniejszej instrukcji student powinien mieć opanowany materiał na temat:

· Protokołu TCP/IP

· Gniazdowej struktury adresowej

· Gniazd protokołu TCP

· Projektowaniu serwerów współbieżnych - dających możliwość jednoczesnego podłączenia

Wielu klientów

Algorytm komunikacji serwera współbieżnego działającego na funkcji fork()

* Konfiguracja aplikacji serwera oraz serwera została omówiona w poprzedniej instrukcji

laboratoryjnej. Serwer współbieżny odpowiedzialny jest za wykonanie zapytania nadesłanych przez klientów. Serwer podczas uruchomienia musi wykonać czynności konfiguracyjne *, kte decydują o jego poprawnym działaniu.

W procesie macierzystym serwer tworzy gniazdo (bind), kte ustawia w tryb nasłuchu (listen), przyjmuje żądanie połączenia wysłane na adres gniazda (accept) oraz tworzy nowy proces potomny odpowiedzialny za bieżące połączenie (fork).

W procesie potomnym serwer prowadzi wymianę danych z podłączonym klientem, po rozłączeniu klienta gniazdo zostaje zwolnione, a proces potomny zakończony, Gdy proces potomny zostaje zakończony, proces macierzysty otrzymuje sygnał SIGCHILD.

Po otrzymaniu sygnału, kończy proces potomny przy pomocy instrukcji signal(SIGCHILD, sig_chld).

Przykładowy program serwera wspłieżnego (wykonującego operacje arytmetyczne):

void sig_chld(int signo)

{

pid_t pid;

int stat;

while ((pid = waitpid(-1,&stat, WNOHANG))>0)

printf("Dziecko %d zatrzymanen", pid);

return;

}

//po funkcji listen

signal(SIGCHLD, sig_chld);

for(;;)

{

clilen = sizeof(cliaddr);

if ((connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen)) < 0)

{

if(errno==EINTR)

continue;

else

err("accept error");

}

if((dzieckopid=fork()) ==0){

close(listenfd);

while ((n = read(connfd, buff, MAXLINE)) > 0)

{

for(j=0; j<sizeof(buff); j++)

{

if(buff[j]=='+'||buff[j]=='-'||buff[j]=='*'||buff[j]=='/'||buff[j]=='%')

{

tempchar=buff[j];

temp=j;

break;

}

else

bufftemp[j]=buff[j];

}

l[0]=atoi(bufftemp);

for(j=temp+1; j<sizeof(buff); j++)

bufftemp[j-temp-1]=buff[j];

l[2]=atoi(bufftemp);

if(tempchar=='+')

wynik=l[0]+l[2];

if(tempchar=='-')

wynik=l[0]-l[2];

if(tempchar=='*')

wynik=l[0]*l[2];

if(tempchar=='/')

{

if (l[2]==0)

{

wyslij(connfd, "Blad dzielenia przez 0n");

bzero(buff, sizeof(buff));

bzero(bufftemp, sizeof(bufftemp));

bzero(l, sizeof(l));

continue;

}

else

wynik=l[0]/l[2];

}

if(tempchar=='%')

wynik=l[0]%l[2];

char wynikstr[MAXLINE];

bzero(wynikstr,sizeof(wynikstr));

sprintf(tabtemp, "%i", wynik);

strcat(wynikstr,"Wynik: ");

strcat(wynikstr, tabtemp);

bzero(buff, sizeof(buff));

bzero(bufftemp, sizeof(bufftemp));

bzero(l, sizeof(l));

if (write(connfd, wynikstr, strlen(wynikstr))<=0)

printf("Blad wysylania");

}

exit(0);

}

close(connfd);

}

}

Serwer odbiera od klienta ciąg znaków (buff), wczytuje je do tablicy (3 elementowej) jako liczby całkowite i wykonuje operacje arytmetyczne w zależności od zawartości otrzymanego ciągu.

2) Zadania do wykonania

Aby zaliczyć laboratorium 4 należy:

· Zmodyfikować aplikację serwera z poprzednich zajęć tak, aby działała współbieżnie.

· Zabezpieczyć programy przed błędami funkcjonowania.

 

KLIENT


#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#define MAXLINE 4096

int err(char* s) {
    printf("%sn", s);
    printf("Errno: %dn", errno);
    fprintf(stderr, "%sn", strerror(errno));
    exit(-1);
}

void wyslij(int sockfd, const char* c) {
    if (write(sockfd, c, strlen(c)) <= 0)
        err("write error");
    printf("wysłałem ");
}

int main(int argc, char **argv) {
   int sockfd, n;
   int i=0;
   char k[100];
   char recvline[MAXLINE+1], buff[MAXLINE+1];
   struct sockaddr_in servaddr;

   if (argc != 3)
      err("Ussage: klient IP_ADDRESS PORT");

   if   ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
      err("socket error");

   bzero(&servaddr, sizeof(servaddr));
   servaddr.sin_family = AF_INET;

   if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) < 0)
      err("Wrong IP_ADDRESS format");
   else
      printf("Address: %sn", argv[1]);

   if ((servaddr.sin_port = htons(atoi(argv[2]))) < 0)
      err("Wrong PORT format");
   else
      printf("Porcik połączenia: %dn", servaddr.sin_port);

   if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
      err("connect error");
      
   while(1){
     bzero(buff,sizeof(buff));
     printf("wprowadź działanie w postaci a + bnq - wyjście z programun");
     fgets(k, sizeof(k), stdin);
     if(k[0]=='q')
       break;
     strcat(buff,k);
     //strcat(buff,"rn");
     wyslij(sockfd, buff);
     //while ((
     n = read(sockfd, recvline, MAXLINE);// > 0) {
     recvline[n] = 0;
     if (fputs(recvline, stdout) == EOF)
            err("fputs error");
   //  }
     if (n < 0)
        err("read error");
   }
   if (close(sockfd) < 0)
         err("close error");
   return 0;
}

_____________________________________________________________________________



SERWER-FOR







#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

#include <signal.h>

#include <sys/wait.h>

#define MAXLINE 4096
#define LISTENQ 1024

void err(char* s) {
printf("%sn", s);
printf("Errno: %dn", errno);
fprintf(stderr, "%sn", strerror(errno));
exit(-1);
}

void wyslij(int sockfd, const char* c) {
if (write(sockfd, c, strlen(c)) <= 0)
err("write error");
// printf("wysłałem %sn",c);
}

/* obsluga sygnalow */
typedef void Sigfunc(int);
Sigfunc* signal(int signo, Sigfunc* func) {
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;
#endif
} else {
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART;
#endif
}
if (sigaction(signo, &act, &oact) < 0)
return SIG_ERR;
return(oact.sa_handler);
}

void sig_chld(int signo) {
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0);
return;
}

int main(int argc, char **argv) {
int listenfd, connfd, kkk;
int l[3], j=0,wynik;
struct sockaddr_in servaddr, kaddr;
char buff[MAXLINE], recvline[MAXLINE],buff2[MAXLINE],str[MAXLINE],z;
int currpos = 0, i, n;
time_t ticks;

/* sygnal SIGCHLD */
if (signal(SIGCHLD, sig_chld) == SIG_ERR)
err("signal error");

if (argc != 2)
err("Ussage: SERWER PORT");

if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
err("socket error");

bzero(&servaddr, sizeof(servaddr));
//servaddr.sin_len = sizeof(servaddr);
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
//servaddr.sin_port = htons(15000);
if ((servaddr.sin_port = htons(atoi(argv[1]))) < 0)
err("Wrong PORT format");

bzero(&kaddr, sizeof(kaddr));

if (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0)
err("bind error");

if (listen(listenfd, LISTENQ) < 0)
err("listen error");

while (1) {
kkk=sizeof(kaddr);
if ((connfd = accept(listenfd, (struct sockaddr *) &kaddr, &kkk)) < 0)
err("accept error");
if( fork()==0 ){
close(listenfd);
while ((n = read(connfd, buff, MAXLINE)) > 0) {
j=0;
for (i = 0; i < n; i++) {
if(j==2) j=0;
//printf("buf[%d]=%cn",i,buff[i]);
if(buff[i]==' '){
currpos=0;
l[j]=atoi(recvline);
if(j==1) z=buff[i-1];
j++;
}
recvline[currpos++] = buff[i];
if (buff[i] == 'n') {
buff[i + 1] = 0;
if (!strcmp(buff, "rn")) {
if (close(connfd))
err("close error");
} else{l[2]=atoi(recvline);
wynik=0;
strcat(buff2, buff);
strcat(buff2," = ");
if(z=='+')
wynik=l[0]+l[2];
if(z=='-')
wynik=l[0]-l[2];
if(z=='*')
wynik=l[0]*l[2];
if(z=='/')
wynik=l[0]/l[2];
if(z=='%')
wynik=l[0]%l[2];

sprintf(str, "%i", wynik);
strcat(buff2,str);
strcat(buff,buff2);
strcat(buff,"n");
bzero(buff2,sizeof(buff2));bzero(l,sizeof(l));
wyslij(connfd, buff);bzero(recvline,sizeof(recvline));currpos = 0;bzero(buff,sizeof(buff));
}
currpos = 0;
break;
}
}
}

}
close(connfd); // ignoruj bledy
}
return 0;
}