1 Sockets Traditionellt har UNIX varit svag på IPC, InterProcess Communication. I augusti 1983 kom en ny IPC-mekanism i 4.2BSD som var enkel om konsistent. I denna version fick man möjlighet att koppla upp sig mot ARPANET. I april 1986 designades hela IPC-systemet om till ett oberoende system i och med lanseringen av 4.3BSD. IPC kan ske mellan Processer i en maskin Processer över ett nätverk Christian Ohlsson, Karlstads universitet 2001 SocketsDatakommunikation II
2 Allmänt om sockets En socket: Är en ändpunkt vid kommunikation Kan knytas till ett namn Existerar i en kommunikationsdomän Har en typ Kommunikationsdomäner Specificerar en protokollstack AF_UNIX: Lokal UNIX-domän. Används inom en dator AF_INET: ARPANETs domän. Används över nätverk Christian Ohlsson, Karlstads universitet 2001 SocketsDatakommunikation II
3 Olika typer av sockets SOCK_STREAM, strömmande överföring [TCP] Pålitlig Sekventiell överföring Inga kopior skapas Ingen maximal storlek på paketen SOCK_DGRAM, datagram överföring [UDP] Opålitlig Viss storlek på paketen SOCK_RAW, ren socket [IP] Christian Ohlsson, Karlstads universitet 2001 SocketsDatakommunikation II
4 Hur skapas en socket En socket skapas med anropet: s = socket(domän, typ, protokoll); Returvärdet är en fildeskriptor (int) Exempel: int s = socket(AF_UNIX, SOCK_STEAM, 0); int s = socket(AF_INET, SOCK_DGRAM, 0); Dessa konstanter finns deklarerade i filerna och Om anropet misslyckades returneras -1 Christian Ohlsson, Karlstads universitet 2001 SocketsDatakommunikation II
5 Namngivning av en socket En socket skapas utan ett namn, men för att kunna användas måste den ges ett namn. De två kommunicerande processer kopplas ihop med en association: AF_UNIX: AF_INET: Hälften av denna association skapas med: bind(socket, name, namelength) Christian Ohlsson, Karlstads universitet 2001 SocketsDatakommunikation II
6 Strukten sockaddr_in Det finns en struct i filen som används för att innehålla information om uppkopplingen. struct sockaddr_in { short sin_family; // Adressfamilj u_short sin_port; // Portnummer in_addr sin_addr; // Internetadress char sin_zero[8] // Oanvänt }; Christian Ohlsson, Karlstads universitet 2001 SocketsDatakommunikation II
7 Adressering Bind fyller i vår struct sockaddr_in med information. Det som fylls i är den information som vi från vår sida vet, dvs informationen lokal adress och port. Exempel struct sockaddr_in server;... server.sin_family = AF_INET; // Internet server.sin_addr.s_addr = INADDR_ANY; // Valfritt NIC server.sin_port = 0; // Valfri port bind(socket, (struct sockaddr *)&sin, sizeof(sin)); Christian Ohlsson, Karlstads universitet 2001 SocketsDatakommunikation II
8 Representation av tal Olika datorer representerar tal olika ”rätt ordning” – network byte order Most significant byte first (big endian) ”min ordning” – host byte order Konvertera tal innan sändning med htonl eller htons Konvertera tal innan sändning med ntohl eller ntohs
9 Ta reda på information gethostname(name,namelen) getpeername(sockfd,name,namelen) getsockname(sockfd,name,namelen) getservent,getservbyname,getservbyport getprotoent, getprotobyname, getprotobynumber gethostbyname(name) gethostbyaddr(addr)
10 Structen hostent Structen hostent innehåller information om en dator och fylls i med gethostbyaddr() eller gethostbyname() struct hostent { char *h_name; // Datorns namn char **h_aliases; // Alias för datorn int h_addrtype; // Adresstypen int h_length; // Adressens storlek char **h_addr_list; // Lista på adresser }; Datakommunikation IISockets Christian Ohlsson, Karlstads universitet 2001
11 Listen Lyssnar efter uppkopplingsbegäran listen (sockfd,backlog) Kan ej användas på datagramsockets backlog anger maxstorleken på kön där uppkopplingsbegäran väntar
12 Accept Accepterar en uppkopplingsbegäran new_sockfd = accept(sockfd,addr,addrlen) En ny socket skapas för kommunikation med den anropade klienten. Fyller structen addr med info om klienten addrlen – efter anrop den aktuella storleken på addr
13 Connect Klienten kopplar upp sig mot servern connect (sockfd,addr_to,addr_to_len) addr_to är adressen till servern
14 Så skapas en uppkoppling En process är server och den andra är klient Servern: Skapar en socket (socket(…)) Ger den ett namn (bind(…)) Väntar på en uppkopplingsbegäran (listen(…)) [TCP] Accepterar uppkopplingsbegäran (accept(…)) [TCP] Klienten Skapar en socket (socket(…)) Ger den ett namn (bind(…)) [UDP] Gör uppkopling mot servern (connect(…)) [TCP] Efter detta har vi en uppkoppling->datautbyte kan ske Christian Ohlsson, Karlstads universitet 2001 SocketsDatakommunikation II
15 Ta emot och skicka data Systemanropen read & write går att använda read (sockfd,buf,bufsize) write (sockfd,buf,bufsize) Send och recv för sockets send (sockfd,buf,bufsize,flags) recv (sockfd,buf,bufsize,flags)
16 Ta emot och skicka datagram Ingen uppkoppling krävs, men adressen får anges varje gång recvfrom(sockfd,buf,bufsize,flags,addr_from,addr_from_len) sendto(sockfd,buf,bufsize,flags,addr_to, addr_to_len) recvmsg(sockfd,msg,flags) sendmsg(sockfd,msg,flags)
Christian Ohlsson, Karlstads universitet 2001 Sockets Datakommunikation II socket bind accept listen socket connect writeread writeread Server Klient Blockerar tills Klienten gör connect Data (request) Data (reply) TCP uppkoppling
18 printsin Funktionen printsin skriver ut information om datorn som begärde en uppkoppling. void printsin(struct sockaddr_in *sin) { struct hostent *gethostbyaddr(), *h; h = gethostbyaddr((char *)&sin->sin_addr, sizeof(int),AF_INET); printf (”Ny uppkoppling från \n",h->h_name); } Christian Ohlsson, Karlstads universitet 2001 SocketsDatakommunikation II
Sockets #include void main(){ int listsock, datasock, length; /* Fildeskriptorer och variabel */ struct sockaddr_in server, client; char ch; if ( (listsock = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) { perror(“Server kunde ej skapa socket"); exit(1); } bzero((char *) &server, sizeof(server)); /* Nolla ut structen */ server.sin_family = AF_INET; /* Internetdomänen */ server.sin_addr.s_addr = htonl(INADDR_ANY); /* Valfritt NIC */ server.sin_port = 0; /* 1:a lediga port */ if (bind(listsock, (struct sockaddr *)&server, sizeof(server)) < 0) { perror(“Server kunde ej binda adressen"); exit(1); } length = sizeof(server); /* Hämta in storleken på structen */ if (getsockname(listsock, (struct sockaddr *)&server, &length) < 0) { perror(“Server kunde ej hämta in namnet"); exit(1); } printf(“Server använder port: %d\n", ntohs(server.sin_port)); listen(listsock,1); /* Initiera lyssnarkön */ length = sizeof(client); /* Hämta in storleken på structen */ if((datasock=accept(listsock,(struct sockaddr *)&client,&length))<0) { perror(“Server kunde ej tillåta ny uppkoppling"); exit(1); } printsin(&client); printf("\nInkommande data:\n"); while ( read(datasock, &ch, 1) == 1) /* Läs från datasocketen */ putchar(ch); /* Skriv ut tecknet som lästs */ putchar('\n'); } Christian Ohlsson, Karlstads universitet 2001 TCP/IP server
Datakommunikation II Sockets #include char msg[] = { ”Detta är ett test" }; /* Teststräng */ void main(int argc, char **argv) { char *servername; /* Namnet på servern */ u_short serverport; /* Port som data skall färdas på */ int datasock; struct sockaddr_in klient; struct hostent *h; if (argc != 3) { fprintf(stderr,”Skriv: klient \n"); exit(1); } servername = argv[1]; /* Hämta in namnet */ serverport = atoi(argv[2]); /* Hämta in porten */ if ( (datasock = socket( AF_INET, SOCK_STREAM, 0 )) < 0 ) { perror(”Klient kunde ej skapa socket"); exit(1); } bzero((char *) &klient, sizeof(klient)); /* Nolla ut structen */ klient.sin_family = AF_INET; if ((h = gethostbyname(servername)) == NULL) { /* Fyll i structen */ perror(”Klient kunde ej hämta namnet"); exit(1); } bcopy((char *)h->h_addr, (char *)&klient.sin_addr, h->h_length); klient.sin_port = htons(serverport); if(connect(datasock,(struct sockaddr *)&klient,sizeof(klient)) < 0) { perror(”Klienten kunde inte koppla upp"); exit(1); } write(datasock, msg, sizeof(msg)); /* Skriv meddelandet på socketen */ close(datasock); /* Stäng socketen */ } Christian Ohlsson, Karlstads universitet 2001 TCP/IP klient