Berkeley Sockets on sovellusohjelmointirajapinta (API), joka on C-kielen sovellusten kehittämiseen tarkoitettu kirjasto , joka tukee prosessien välistä viestintää (IPC), jota usein käytetään tietokoneverkoissa .
Berkeley- socketit (tunnetaan myös nimellä BSD socket API ) ilmestyivät ensimmäisen kerran API:na 4.1BSD Unix -käyttöjärjestelmässä (julkaistu vuonna 1982) [1] . Kuitenkin vasta vuonna 1989 UC Berkeley pystyi julkaisemaan versioita käyttöjärjestelmästä ja verkkokirjastosta ilman tekijänoikeudella suojatun Unixin AT&T -lisenssirajoituksia.
Berkeley Sockets API on muodostanut de facto abstraktiostandardin verkkovastakkeille. Useimmat muut ohjelmointikielet käyttävät samanlaista käyttöliittymää kuin C API.
STREAMS-pohjainen Transport Layer Interface (TLI) API on vaihtoehto socket API:lle. Berkeley Sockets API on kuitenkin erittäin suosittu suosio ja toteutusmäärien suhteen.
Berkeley socket interface on API , joka mahdollistaa viestinnän tietokoneiden välillä tai prosessien välillä samassa tietokoneessa. Tämä tekniikka voi toimia useiden erilaisten I/O-laitteiden ja -ohjainten kanssa, vaikka niiden tuki riippuu käyttöjärjestelmän toteutuksesta . Tämä käyttöliittymän toteutus on TCP/IP :n perusta, minkä vuoksi sitä pidetään yhtenä Internetin perustana olevista perustekniikoista . Socket-tekniikka kehitettiin ensimmäisen kerran UC Berkeleyssä käytettäväksi UNIX - järjestelmissä. Kaikissa nykyaikaisissa käyttöjärjestelmissä on Berkeley socket -rajapinnan toteutus, koska siitä on tullut standardi Internet-yhteyden muodostamisen käyttöliittymä.
Ohjelmoijat voivat käyttää socket-liitäntää kolmella eri tasolla, joista tehokkain ja perustavanlaatuisin on raakapistorasio . Melko pieni määrä sovelluksia joutuu rajoittamaan toteuttamiensa lähtevien yhteyksien hallintaa, joten raaka socket -tuki oli tarkoitettu vain tietokoneille, joita käytetään Internetiin liittyviin teknologioihin perustuvaan kehitykseen. Myöhemmin useimmat käyttöjärjestelmät ovat ottaneet käyttöön tuen niille, mukaan lukien Windows .
Berkeley Sockets Software Library sisältää monia aiheeseen liittyviä otsikkotiedostoja.
<sys/socket.h> BSD-socketin perustoiminnot ja tietorakenteet. <netinet/in.h> Osoite-/protokollaperheet PF_INET ja PF_INET6. Niitä käytetään laajasti Internetissä, ja ne sisältävät IP-osoitteita sekä TCP- ja UDP-porttinumeroita. <sys/un.h> PF_UNIX/PF_LOCAL osoiteperhe. Käytetään paikalliseen viestintään samassa tietokoneessa toimivien ohjelmien välillä. Ei koske tietokoneverkkoja. <arpa/inet.h> Toiminnot numeeristen IP-osoitteiden käsittelyyn. <netdb.h> Toiminnot protokollien ja isäntänimien muuntamiseen numeerisiksi osoitteiksi. Paikallisia tietoja käytetään DNS:n tapaan.socket()luo yhteyden päätepisteen ja palauttaa kahvan osoitteeseen . socket()vaatii kolme argumenttia:
Funktio palauttaa −1virheen. Muussa tapauksessa se palauttaa määritettyä kahvaa edustavan kokonaisluvun.
Prototyyppi #include <sys/types.h> #include <sys/socket.h> int socket ( int domain , int type , int protokolla );Funktiot gethostbyname()ja gethostbyaddr()palauttavat osoittimen struct hostent -tyyppiseen objektiin, joka kuvaa Internet-isäntää nimen tai osoitteen perusteella. Tämä rakenne sisältää joko nimipalvelimelta saatuja tietoja tai mielivaltaisia kenttiä riviltä /etc/hosts. Jos paikallinen nimipalvelin ei ole käynnissä, nämä rutiinit etsivät hakemistosta /etc/hosts. Funktiot käyttävät seuraavat argumentit:
Funktiot palauttavat virheen yhteydessä NULL-osoittimen. Tässä tapauksessa ylimääräinen kokonaisluku h_errno voidaan tarkistaa virheen tai virheellisen tai tuntemattoman isännän havaitsemiseksi. Muussa tapauksessa palautetaan kelvollinen struct hosten * .
Prototyypit struct hostent * gethostbyname ( const char * nimi ); struct hostent * gethostbyaddr ( const void * addr , int len , int type );connect() Muodostaa yhteyden palvelimeen. Palauttaa virhekoodia edustavan kokonaisluvun: 0 tarkoittaa onnistumista ja -1 virhettä.
Jotkin pistorasian tyypit ovat yhteydettömiä, varsinkin UDP-vastakkeet. Heille yhteys saa erityisen merkityksen: tiedon lähetyksen ja vastaanottamisen oletuskohde määrätään välitetylle osoitteelle, jolloin toimintoja voidaan käyttää kuten send()yhteydettömissä recv()pistorasioissa.
Varattu palvelin voi hylätä yhteysyrityksen, joten tietyntyyppiset ohjelmat on määritettävä yrittämään yhteyttä uudelleen.
Prototyyppi #include <sys/types.h> #include <sys/socket.h> int connect ( int sockfd , const struct sockaddr * serv_addr , socklen_t addrlen );bind()sitoo socketin tiettyyn osoitteeseen. Kun pistoke luodaan :lla socket(), se liitetään johonkin osoiteperheeseen, mutta ei tiettyyn osoitteeseen. Ennen kuin pistorasia voi vastaanottaa saapuvia yhteyksiä, se on sidottava osoitteeseen. bind()vaatii kolme argumenttia:
Palauttaa 0 onnistumisesta ja -1 virheestä.
Prototyyppi #include <sys/types.h> #include <sys/socket.h> int bind ( int sockfd , const struct sockaddr * my_addr , socklen_t addrlen );listen()valmistelee sidotun pistorasian vastaanottamaan saapuvat yhteydet (kutsutaan "kuunteluun"). Tämä toiminto koskee vain liitäntätyyppejä SOCK_STREAMja SOCK_SEQPACKET. Siinä on kaksi argumenttia:
Kun yhteys on hyväksytty, se poistetaan jonosta. Onnistuessa palautetaan 0, jos virhe, −1.
Prototyyppi #include <sys/socket.h> int kuuntele ( int sockfd , int backlog );accept()käytetään hyväksymään yhteyspyyntö etäisännältä. Hyväksyy seuraavat argumentit:
Funktio palauttaa hyväksyttyyn yhteyteen liittyvän socket-kuvaajan tai -1 virheen sattuessa.
Prototyyppi #include <sys/types.h> #include <sys/socket.h> int hyväksy ( int sockfd , struct sockaddr * cliaddr , socklen_t * addrlen );Kun olet luonut pistorasian, voit asettaa sille lisäparametreja. Tässä on joitain niistä:
Berkeley-pistorasiat voivat toimia kahdessa tilassa: estävä tai ei-esto. Estovastake ei palauta ohjausta ennen kuin se on lähettänyt (tai vastaanottanut) kaikki toiminnolle määritetyt tiedot. Tämä koskee vain Linux-järjestelmiä. Muissa järjestelmissä, kuten FreeBSD:ssä, on luonnollista, että estävä socket ei lähetä kaikkea dataa (mutta voit asettaa send()- tai recv()-lipun MSG_WAITALL). Sovelluksen tulee tarkistaa palautusarvo seuratakseen, kuinka monta tavua lähetettiin/vastaanotettiin, ja lähetettävä uudelleen tällä hetkellä käsittelemättömät tiedot [2] . Tämä voi johtaa ongelmiin, jos socket jatkaa kuuntelemista: ohjelma saattaa jumittua, koska socket odottaa tietoja, joita ei ehkä koskaan saavu.
Socket määritetään yleensä estäväksi tai ei-estoiseksi käyttämällä fcntl()tai -toimintoja ioctl().
Tietojen siirtämiseen voit käyttää vakiotoimintoja tiedostojen lukemiseen / kirjoittamiseen readja write, mutta on olemassa erityisiä toimintoja tiedon siirtämiseen pistorasian kautta:
On huomattava, että käytettäessä TCP-protokollaa (tyyppisiä sockets SOCK_STREAM) on mahdollisuus vastaanottaa vähemmän dataa kuin lähetettiin, koska kaikkia tietoja ei ole vielä vastaanotettu, joten sinun on joko odotettava, kunnes funktio recvpalauttaa 0 tavua, tai aseta MSG_WAITALLfunktiolle lippu recv, joka pakottaa sen odottamaan siirron loppuun asti. Muuntyyppisissä socketeissa lippu MSG_WAITALLei muuta mitään (esimerkiksi UDP:ssä koko paketti = koko viesti). Katso myös Lukitsevat ja estävät pistorasiat.
Järjestelmä ei vapauta puhelun allokoimia resursseja socket()ennen kuin puhelu tapahtuu close(). Tämä on erityisen tärkeää, jos puhelu connect()epäonnistui ja sitä voidaan yrittää uudelleen. Jokaisella kutsulla socket()on oltava vastaava kutsu close()kaikilla mahdollisilla suorituspoluilla. <unistd.h>-otsikkotiedosto on lisättävä tukemaan sulkemistoimintoa.
Järjestelmäkutsun suorittamisen tuloksena close()on vain kutsua liitäntää pistokkeen sulkemiseksi, ei itse pistokkeen sulkemiseksi. Tämä on komento ytimelle sulkea socket. Joskus palvelinpuolella socket voi mennä lepotilaan TIME_WAITjopa 4 minuutiksi. [yksi]
TCP toteuttaa yhteyden käsitteen. Prosessi luo TCP-socketin kutsumalla funktiota socket()parametreilla PF_INETtai PF_INET6sekä SOCK_STREAM(Stream socket) ja IPPROTO_TCP.
Yksinkertaisen TCP-palvelimen luominen koostuu seuraavista vaiheista:
TCP-asiakkaan luominen on seuraava:
UDP perustuu yhteydettömään protokollaan, eli protokollaan, joka ei takaa tiedon toimittamista. UDP-paketit voivat saapua epäkunnossa, olla päällekkäisiä ja saapua useammin kuin kerran tai jopa olla saapumatta määränpäähän ollenkaan. Näiden vähimmäistakuiden vuoksi UDP on huomattavasti TCP:tä huonompi. Yhteyden muodostamatta jättäminen tarkoittaa, että kahden isännän välillä ei ole virtaa tai yhteyksiä, koska tiedot saapuvat sen sijaan datagrammeissa ( Datagram Socket ).
UDP-osoiteavaruus, UDP-porttinumeroiden alue (TSAP ISO-terminologiassa), on täysin erillinen TCP-porteista.
Koodi voi luoda UDP-palvelimen porttiin 7654 seuraavasti:
int sock = socket ( PF_INET , SOCK_DGRAM , IPPROTO_UDP ); struct sockaddr_insa ; _ int sidottu ; ssize_t resize ; socklen_t * osoite_len = NULL ; sa . sin_addr . s_addr = htonl ( INADDR_ANY ); sa . sin_portti = htons ( 7654 ); sidottu = sitoa ( sukka , ( struct sockaddr * ) & sa , sizeof ( struct sockaddr ) ); jos ( sidottu < 0 ) fprintf ( stderr , "bind(): virhe %s \n " , strerror ( errno ) );bind() sitoo socketin osoite/portti-pariin.
kun ( 1 ) { printf ( "recv testi.... \n " ); resize = recvfrom ( sukka , ( void * ) Hz , 100 , 0 , ( struct sockaddr * ) & sa , osoite_len ); jos ( muuta kokoa < 0 ) fprintf ( stderr , "Virhe %s \n " , strerror ( errno ) ); printf ( "koko: %d \n " , muuta kokoa ); nukkua ( 1 ); printf ( "datagrammi: %s \n " , hz ); }Tällainen ääretön silmukka vastaanottaa kaikki porttiin 7654 saapuvat UDP-datagrammit käyttämällä recvfrom() -funktiota . Funktio käyttää parametreja:
Yksinkertainen esitys UDP-paketin lähettämisestä, joka sisältää "Hei!" osoitteeseen 127.0.0.1, portti 7654, näyttää suunnilleen tältä:
#include <stdio.h> #include <errno.h> #include <string.h> #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <unistd.h> /* kutsua close() pistorasiassa */ int main ( tyhjä ) { int sukka ; struct sockaddr_insa ; _ int bytes_sent ; const char * buffer = "Hei!" ; int puskurin_pituus ; puskurin_pituus = strlen ( puskuri ) + 1 ; sukka = socket ( PF_INET , SOCK_DGRAM , IPPROTO_UDP ); jos ( sukka == -1 ) { printf ( "Virhe luotaessa pistoketta" ); paluu 0 ; } sa . syn_family = PF_INET ; sa . sin_addr . s_addr = htonl ( 0x7F000001 ); sa . sin_portti = htons ( 7654 ); tavua lähetetty = lähetä ( sukka , puskuri , strlen ( puskuri ) + 1 , 0 , ( struct sockaddr * ) & sa , sizeof ( struct sockaddr_in ) ); jos ( tavut_lähetetyt < 0 ) printf ( "Virhe lähetettäessä pakettia: %s \n " , strerror ( errno ) ); sulkea ( sukka ); paluu 0 ; }POSIX -standardin sisältämä socket-liitännän "de jure" määritelmä , joka tunnetaan paremmin nimellä: