1 / 18

Luku 5

Luku 5. Sisältö: TCP echo palvelin ja asiakas Posix Signaalit SIGCHLD, wait (2), waitpid(2) Datan lähettäminen. TCP echo-palvelin, pääohjelma. #include "unp.h" int main(int argc, char **argv) { int listenfd, connfd; pid_t childpid; socklen_t clilen;

Download Presentation

Luku 5

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Luku 5 • Sisältö: • TCP echo palvelin ja asiakas • Posix Signaalit • SIGCHLD, wait (2), waitpid(2) • Datan lähettäminen

  2. TCP echo-palvelin, pääohjelma • #include "unp.h" • int • main(int argc, char **argv) • { • int listenfd, connfd; • pid_t childpid; • socklen_t clilen; • struct sockaddr_in cliaddr, servaddr; • listenfd = Socket(AF_INET, SOCK_STREAM, 0); • bzero(&servaddr, sizeof(servaddr)); • servaddr.sin_family = AF_INET; • servaddr.sin_addr.s_addr = htonl(INADDR_ANY); • servaddr.sin_port = htons(SERV_PORT); • Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); • Listen(listenfd, LISTENQ); • for ( ; ; ) { • clilen = sizeof(cliaddr); • connfd = Accept(listenfd, (SA *) &cliaddr, &clilen); • if ( (childpid = Fork()) == 0) { /* child process */ • Close(listenfd); /* close listening socket */ • str_echo(connfd); /* process the request */ • exit(0); • } • Close(connfd); /* parent closes connected socket */ • } • }

  3. str_echo() • #include "unp.h" • void • str_echo(int sockfd) • { • ssize_t n; • char buf[MAXLINE]; • again: • while ( (n = read(sockfd, buf, MAXLINE)) > 0) • Writen(sockfd, buf, n); • if (n < 0 && errno == EINTR) • goto again; • else if (n < 0) • err_sys("str_echo: read error"); • }

  4. TCP echo-asiakas • #include "unp.h" • int • main(int argc, char **argv) • { • int sockfd; • struct sockaddr_in servaddr; • if (argc != 2) • err_quit("usage: tcpcli <IPaddress>"); • sockfd = Socket(AF_INET, SOCK_STREAM, 0); • bzero(&servaddr, sizeof(servaddr)); • servaddr.sin_family = AF_INET; • servaddr.sin_port = htons(SERV_PORT); • Inet_pton(AF_INET, argv[1], &servaddr.sin_addr); • Connect(sockfd, (SA *) &servaddr, sizeof(servaddr)); • str_cli(stdin, sockfd); /* do it all */ • exit(0); • }

  5. str_cli() • #include "unp.h" • void • str_cli(FILE *fp, int sockfd) • { • char sendline[MAXLINE], recvline[MAXLINE]; • while (Fgets(sendline, MAXLINE, fp) != NULL) { • Writen(sockfd, sendline, strlen(sendline)); • if (Readline(sockfd, recvline, MAXLINE) == 0) • err_quit("str_cli: server terminated prematurely"); • Fputs(recvline, stdout); • } • }

  6. Normaali yhteyden katkaisu • Käyttäjä antaa loppumerkin, fgets palauttaa nollaosoittimen, str_cli() poistuu, asiakasohjelma lopetetaan exit() kutsulla • Kernel sulkee asiakkaan socketin, FIN lähetetään • Palvelin vastaa ACK viestillä. • Palvelimen readline palauttaa 0, str_echo poistuu ja palvelimen lapsiprosessi kutsuu exit(). • Lapsiprosessin socketit suljetaan • Palvelin lähettää FIN viestin • Asiakas vastaa ACK viestillä • SIGCHLD lähetetään palvelimen pääprosessille

  7. POSIX signaalit • Softakeskeytyksiä • Kernel lähettää tai prosessi lähettää toiselle kill() kutsulla • Signaalin käsittelijä (action, disposition) void handler(int signo)

  8. sigaction • int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); • struct sigaction { • void (*sa_handler)(int); • void (*sa_sigaction)(int, siginfo_t *, void *); • sigset_t sa_mask; • int sa_flags; • void (*sa_restorer)(void); • }

  9. Liput • SA_NOCLDSTOP – Ei SIGCHLD signaalia • SA_NOCLDWAIT – Ei lapsia zombeiksi • SA_RESETHAND – Resetoidaan handleri • SA_ONSTACK - Oma pino • SA_RESTART - Systeemikutsujen uudelleen käynnistys • SA_NODEFER - käsittelijää voidaan kutsua kesken • SA_SIGINFO - käsittelijä ottaa 3 argumenttia

  10. lib/signal • /* include signal */ • #include "unp.h" • 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; /* SunOS 4.x */ • #endif • } else { • #ifdef SA_RESTART • act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */ • #endif • } • if (sigaction(signo, &act, &oact) < 0) • return(SIG_ERR); • return(oact.sa_handler); • } • /* end signal */ • Sigfunc * • Signal(int signo, Sigfunc *func) /* for our signal() function */ • { • Sigfunc *sigfunc; • if ( (sigfunc = signal(signo, func)) == SIG_ERR) • err_sys("signal error"); • return(sigfunc); • }

  11. Käsittelijöistä • Saa käyttää ainoastaan re-entrantteja kirjastokutsuja • pitää tallentaa ja palauttaa errno

  12. SIGCHLD käsittelijä, ensimmäinen yritys • #include "unp.h" • void • sig_chld(int signo) • { • pid_t pid; • int stat; • pid = wait(&stat); • printf("child %d terminated\n", pid); • return; • } • MIKSI EI TOIMI?

  13. SIGCHLD käsittelijä, ensimmäinen yritys • Signaaleja voi tulla vain yksi, vaikka useita lapsia olisi poistunut • Tuki uudelleen käynnistykselle on optionaalinen

  14. SIGCHLD käsittelijä, oikea vastaus • #include "unp.h" • void • sig_chld(int signo) • { • pid_t pid; • int stat; • while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0) • printf("child %d terminated\n", pid); • return; • }

  15. TCP echo palvelin, toimiva versio • #include "unp.h" • int • main(int argc, char **argv) • { • int listenfd, connfd; • pid_t childpid; • socklen_t clilen; • struct sockaddr_in cliaddr, servaddr; • void sig_chld(int); • listenfd = Socket(AF_INET, SOCK_STREAM, 0); • bzero(&servaddr, sizeof(servaddr)); • servaddr.sin_family = AF_INET; • servaddr.sin_addr.s_addr = htonl(INADDR_ANY); • servaddr.sin_port = htons(SERV_PORT); • Bind(listenfd, (SA *) &servaddr, sizeof(servaddr)); • Listen(listenfd, LISTENQ); • Signal(SIGCHLD, sig_chld); /* must call waitpid() */ • for ( ; ; ) { • clilen = sizeof(cliaddr); • if ( (connfd = accept(listenfd, (SA *) &cliaddr, &clilen)) < 0) { • if (errno == EINTR) • continue; /* back to for() */ • else • err_sys("accept error"); • } • if ( (childpid = Fork()) == 0) { /* child process */ • Close(listenfd); /* close listening socket */ • str_echo(connfd); /* process the request */ • exit(0); • } • Close(connfd); /* parent closes connected socket */ • } • }

  16. wait ja waitpid • pid_t wait(int *status) • pid_t waitpid(pid_t pid, int *status, int options); • pid: • alle -1 odotetaan kaikkia lapsia prosessiryhmästä • -1 odotetaan kaikkia lapsia • 0 odotetaan kaikkia lapsia, joilla sama prosessiryhmä vanhemman kanssa • yli 0 odotetaan tiettyä prosessia

  17. Datan lähettäminen • Teksti • Binääri • Datatyyppien koot (käytä uint8_t, uint16_t jne) • Big endian/ little endian (määrittele konversio metodit) • Struktuurien jäsenten sijoitus (käytä __attribute_packed() ) • Teksti vs. Data

More Related