Interprosess kommunikasjon Berkeley Sockets Hvordan få to maskiner til å snakke sammen Maskin A...... typedef struct { char sawreceive; char sawsend; int packetpointer; char buf[packetlength+1]; linksession; SOCKET Maskin B...... typedef struct { char sawreceive; char sawsend; int packetpointer; char buf[packetlength+1]; linksession; SOCKET Sockets 1 Sockets 2 Hva må programmene gjøre? Hvordan identifiserer jeg hvem jeg vil snakke til? Program A Opprette en Socket (Opprette forbindelse) Kall på read/write Fjern Socketen Program B Opprette en Socket (Opprette forbindelse) Kall på read/write Fjern Socketen Maskinen ved internettadresse Applikasjonen/tjenesten/programmet ved portnummer en del standardapplikasjoner (f. eks finger og remote login) har sitt eget velkjente portnummer. Sockets 3 Sockets 4
Hva er en socket? Typer En peker til en Transport Kontroll Blokk (TCB). TCB består av to deler: En del som beskriver alle attributtene og tilstandsvariablene som trengs her. En del som beskriver det som trengs å vite om makkeren. Datagram (UDP) Pakkeorientert Best effort (Pakker kan bli borte) Forbindelsesløs Pålitelig (TCP) Strømorientert Alt som blir sendt kommer fram Forbindelsesorientert Sockets 5 Sockets 6 Hvordan skaffer jeg meg en socket? domain? type? protokoll? int sock,domain,type,protocol; sock=socket(domain,type,protokol) domain: AF_UNIX, AF_INET, type: SOCK_STREAM, SOCK_DGRAM, protokol: IPPROTO_TCP,... TCP UDP type IP Nett1 Nett2 Nett3 domain Sockets 7 Sockets 8
Binding av eget endepunkt Hvordan assosiere en adresse og et portnummer med en socket? int status, sock, addrlen; struct sockaddr_in *address; <Internettadressen og portnummeret settes i structen address. Eksempel på dette om et lite øyeblikk> bind(sock, address, addrlen); Sockets 9 Bygging av adressestruct Enten bzero(&serveraddr, sizeof(serveraddr)); /* Finn internettadressen ved oppslag i DNS. */ hostp = gethostbyname("mjollnir.ifi.uio.no"); /* Sett adressen inn i serverstructen */ memcpy((void *) &serveraddr.sin_addr, hostp->h_addr, hostp->h_length); Eller Oversett portnummeret til nettverksformat bzero(&serveraddr, sizeof(serveraddr)); /* Sett internettadressen til denne maskinen sine adresser */ serveraddr.sin_addr.s_addr = INADDR_ANY; Denne maskinen sine adresser Sockets 10 Forbindelsesetablering Klientsiden: Forbindelsesetablering Tjenersiden sock = socket(domain,type,protocol); <bygg opp adressen til serveren i struct en address > connect(sock, address, addresslen); <connect blokkerer inntil forbindelsen er etablert> read(sock,buf,buflen); send(sock,buf,buflen); sock = socket(domain,type,protocol); <bygg opp adressen til denne tjeneren i struct en address > bind(sock, address, addresslen); listen(sock, SOMAXCONN); /* SOMAXCONN er en konstant som gir en pasende kølengde */ newsock = accept(sock,fromaddr,fromlen); <accept blokkerer inntil en connect-request foreligger> read(newsock,,); send(newsock,,); Sockets 11 Sockets 12
Fjerning av socket Eksempel enkel klient close(sock); Merk at semantikken til close er avhengig av hvilken protokoll som kjøres noen implementasjoner kaster alle data som var underveis når close ble utført. #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <string.h> /* deklarasjon av litt datastruktur */ struct hostent *hostp; char buf[11]; main(){ /* Opprett socket */ sock = socket(af_inet, SOCK_STREAM, IPPROTO_TCP); bzero((void *) &serveraddr, sizeof(serveraddr)); /* Finn internettadressen ved oppslag i DNS. */ hostp = gethostbyname("mjollnir.ifi.uio.no"); /* Sett adressen inn i serverstructen */ memcpy((void *) &serveraddr.sin_addr, hostp->h_addr, hostp->h_length); Sockets 13 Sockets 14 Enkel klient forts. Eksempel enkel tjener /* Koble opp */ connect(sock, (struct sockaddr *)&serveraddr, sizeof serveraddr); /* Send data */ write(sock, "Hei verden!", 11); /* les data fra forbindelsen */ read(sock, buf,11); /* legg til et termineringstegn, og skriv ut til skjerm */ buf[11] = '\0'; printf("%s \n",buf); /* Steng socketen */ close(sock); #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <string.h> struct sockaddr_in serveraddr, clientaddr; int clientaddrlen; int request_sock, new_sock; char buf[13]; main() { /* Opprett request-socket */ request_sock = socket(af_inet, SOCK_STREAM, IPPROTO_TCP); Denne maskinen /* Opprett adressestruct */ sin adresse bzero((void *) &serveraddr, sizeof(serveraddr)); serveraddr.sin_addr.s_addr = INADDR_ANY; Oversett portnummeret /* bind adressen til socketen */ Til nettverksformat bind(request_sock, (struct sockaddr *)&serveraddr, sizeof serveraddr); Sockets 15 /* aktiver lytting på socketen */ listen(request_sock, SOMAXCONN); Kølengden til Lytte-socketen Sockets 16
Enkel tjener forts. Generelt for de fleste socketkall /* motta en forbindelse */ new_sock = accept(request_sock,(struct sockaddr *)&clientaddr, &clientaddrlen); /* les data fra forbindelsen, og skriv dem ut */ read(new_sock, buf,11); printf("%s \n",buf); /* Send data tilbake over forbindelsen */ write(new_sock, buf,11); /* Steng socketene */ close(new_sock); close(request_sock); Merk at kall på systemfunksjoner som har med kommunikasjon å gjøre som regel skal kunne feile uten at hele programmet gir opp: if ((sock=socket(domain,type,protocol))<0){ printf( Passende feilmelding ); Sockets 17 Sockets 18 Eksempel enkel klient igjen Enkel klient forts. #include <netinet/in.h> #include <netdb.h> #include <stdio.h> #include <string.h> struct hostent *hostp; char buf[13]; /* Koble opp */ if (connect(sock, (struct sockaddr *)&serveraddr, sizeof serveraddr) < 0) { (void) close(sock); printf("feil under connect\n"); main() {/* Opprett socket */ if ((sock = socket(af_inet, SOCK_STREAM, IPPROTO_TCP)) < 0) { printf("feil under oppreting av socket\n"); bzero((void *) &serveraddr, sizeof(serveraddr)); /* Finn internettadressen ved oppslag i DNS. */ if ((hostp = gethostbyname("mjollnir")) == 0) { printf("ukjent maskin \n"); Sockets 19 /* Sett adressen inn i serverstructen */ memcpy((void *) &serveraddr.sin_addr, hostp->h_addr, hostp->h_length); /* Send data */ write(sock, "Hei verden!", 11); /* les data fra forbindelsen, og skriv dem ut til skjerm */ read(sock, buf,11); buf[11] = '\0'; printf("%s \n",buf); /* Steng socketen */ if (close(sock)) printf("feil under close\n"); Sockets 20
Men Sendte data kan komme frem omgruppert i forhold til hvordan de ble sendt Kompilatoren kan omgruppere, drivere kan omgruppere, og pakker fragmenteres og reassembleres i nettet. Rekkefølgen for mottak er den samme (TCP), men data som ble sendt sammen kan komme frem hver for seg. Et kall på read(sock, buf, 10) kan derfor gi færre enn 10 tegn. Kallet read(sock, buf, 10) returnerer med det antall tegn som faktisk ble lest. Sockets 21 En Tryggere read-prosedyre char safereadbyte(so) int so; { int bytes; char buf[1]; bytes = read(so, buf, 1); if (bytes<0) { perror("error in saferead"); if (close(so)) perror("close"); if (bytes<=0) { printf("server: end of file on %d\n",so); if (close(so)) perror("close"); return buf[0]; int saferead(so,buf, l) int so; char buf[]; int l; { int i; for (i=0; i<l; i++){ buf[i]=safereadbyte(so); return l; Men denne blokkerer dersom den ikke får det antall tegn den ber om. Sockets 22 Aktuelle prosedyrer Formatprosedyrer htonl,ntohl,htons,ntohs For dere er disse kun aktuelle for portnummere Ikkeblokkerende vent på input/ multipleksing fra flere inputkilder (f.eks terninal/nettverk) select,.. Litteratur Berkeley UNIX System Calls and Interprocess Communication Lawrence Besaw, University of Wisconsin (tilgjengelig via kurset sine web-sider) De eksemplene som er forelest her er også nedlastbare fra web-sidene. De danner et godt utgangspunkt for programmering av den obligatoriske oppgaven. En mengde bøker... Sockets 23 Sockets 24