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 *, kte decydują o jego poprawnym działaniu.
W procesie macierzystym serwer tworzy gniazdo (bind), kte 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;
}