Stopcontact (software)

Van Wikipedia, de gratis encyclopedie
Spring naar navigatie Spring naar zoeken

Een socket (van Engelse basis, connector of socket) is een door het besturingssysteem geleverd object dat als communicatie-eindpunt dient. Een programma gebruikt sockets om gegevens uit te wisselen met andere programma's. Het andere programma kan op dezelfde computer staan ​​( interprocescommunicatie ) of op een andere computer die via het netwerk toegankelijk is. Communicatie via sockets is meestal bidirectioneel , wat betekent dat gegevens zowel kunnen worden ontvangen als verzonden via de socket.

functionaliteit

Algemeen werkingsprincipe:

Sockets vormen een platformonafhankelijke, gestandaardiseerde interface ( API ) tussen de netwerkprotocolimplementatie van het besturingssysteem en de eigenlijke applicatiesoftware . Een computerprogramma vraagt ​​een socket aan bij het besturingssysteem. Het besturingssysteem is verantwoordelijk voor het beheer van alle gebruikte sockets en de bijbehorende verbindingsinformatie.

Internet stopcontacten

Internetaansluitingen maken communicatie mogelijk met behulp van bepaalde communicatieprotocollen . Een algemeen onderscheid kan worden gemaakt tussen stroomsockets en datagram sockets: stroomsockets communiceren via een karakter gegevensstroom ; Datagram-sockets over individuele berichten. Bij netwerkcommunicatie gebruiken stream-sockets meestal TCP , datagram-sockets meestal UDP . TCP is betrouwbaarder, de volgorde en aflevering van pakketten zijn gegarandeerd (principe: alles of niets). UDP is efficiënter en flexibeler voor bepaalde taken, vaak sneller (qua tijd) - de volgorde en levering van de pakketten zijn echter niet gegarandeerd (duplicaten zijn nog steeds mogelijk).

Terwijl stream-sockets en datagram-sockets de TCP- of UDP- header van een datapakket meestal verbergen en automatisch laten instellen, laten onbewerkte sockets (Raw: Raw) hun eigen TCP- en UDP-headers maken. Raw sockets worden het meest waarschijnlijk gebruikt in netwerkgerelateerde toepassingen, b.v. B. voor routers , pakketsniffers of pakketinjectie .

Een socket is meestal het verbindingspunt met een specifiek programma op afstand, weergegeven door zijn adresinformatie (bijvoorbeeld IP-adres en poortnummer). De socket zelf krijgt natuurlijk ook zijn eigen adresgegevens. Een Internet socket -adres van de AF_INET familie wordt vertegenwoordigd door de volgende informatie:

  • sin_family , sin_family de bijbehorende sin_family van het netwerk (bijv. AF_INET = adresfamilie internetadres)
  • het identificatienummer van de localhost / zijn 32-bits IP-adres
  • het poortnummer van de localhost / 16 bit

Deze informatie is echter afhankelijk van het gebruikte protocol . Meestal is de adresinformatie op internet het IP-adres en de poort . Bij UNIX Domain Sockets ( zie hieronder) bestaat de identificatie uit een bestandspadnaam en de AF_UNIX-adresfamilie.

Een server kan ofwel wachten op verzoeken van een specifiek adres (en zich vanaf het begin aan dit adres binden) of wachten op verzoeken op alle adressen op zijn computer. Sommige protocollen hebben een zogenaamd wildcard-adres waarvoor een of meer delen van de adresgegevens niet specifiek zijn. In het voorbeeld van TCP/IP en UDP/IP is alleen het poortnummer relevant voor een wildcard adres, d.w.z. er wordt een speciaal (ongeldig) IP-adres opgegeven om aan te geven dat verbindingen op alle IP-adressen geaccepteerd moeten worden. Onder Linux is dit wildcard- adres 0.0.0.0 (symbolische constante INADDR_ANY).

Wanneer de server een verzoek van een client ontvangt, wordt de aangesloten server-socket afgeleid van de luisterende server-socket: de oorspronkelijke server-socket blijft behouden en blijft wachten op nieuwe verbindingen, terwijl een nieuwe socket voor de specifieke client wordt geopend, die wordt alleen gebruikt voor communicatie met deze ene klant. Deze blijft staan ​​totdat de verbinding met de client van een van beide kanten wordt verbroken. Deze afleiding kan worden gebruikt om een ​​parallelle serverarchitectuur te creëren waarin de server zichzelf fort op een verzoek en een onderliggend proces het verzoek zelf beantwoordt.

Dit betekent dat een server-socket die is aangesloten op een client-socket exact hetzelfde IP-adres en poortnummer heeft als de luisterende server-socket. Het onderscheid tussen gelijktijdige clientverbindingen met dezelfde server wordt daarom gemaakt door het paar server-socket en client-socket. Dit paar moet te allen tijde uniek zijn voor elk van de betrokken communicatiepartners. Als voorbeeld wordt een HTTP-server gegeven die luistert op poort 80. De verbindingen van de server met verschillende clients leiden tot de volgende unieke "Verbonden" socketparen op de servercomputer:

(<Server-IP>: 80; <Client_A-IP>: <Client_A_Port_1>), (<Server-IP>: 80; <Client_A-IP>: <Client_A_Port_2>), (<Server-IP>: 80; < Client_B-IP>: <Client_B_Port_1>) enz.

Socket communicatie volgorde

Stroomaansluitingen

Klantzijde :

  1. socket maken
  2. Verbind de gemaakte socket met het serveradres waarvan de gegevens moeten worden opgevraagd
  3. Gegevens verzenden en ontvangen
  4. sluit eventueel de socket af ( shutdown() , close() )
  5. Loskoppelen, stopcontact sluiten

Server-kant :

  1. Server-socket maken
  2. Binding van de socket aan een adres (poort) via welke verzoeken worden geaccepteerd
  3. wachten op vragen
  4. Accepteer het verzoek en maak zo een nieuw socketpaar voor deze client
  5. Verwerking van het clientverzoek op de nieuwe client-socket
  6. Sluit de client-socket weer.

Datagram-sockets

Klantzijde :

  1. socket maken
  2. Verzenden naar adres

Server-kant :

  1. socket maken
  2. Bind socket
  3. wachten op pakketten

Sockets en communicatie tussen processen

Unix-besturingssystemen gebruiken voor lokale communicatie tussen processen, genaamd POSIX Local Inter-Process Communication-sockets (ook IPC-sockets , of "inter-process communicatie-sockets", of Unix-domein-sockets). Ook hier zijn er datagram- en stream-sockets; Omdat de communicatie echter plaatsvindt in de kernel, gedragen stream- en datagram-sockets zich zeer gelijkaardig (er is bijvoorbeeld ook geen risico op gegevensverlies met datagram-sockets). Een Unix-domeinsocket wordt weergegeven als een speciaal bestand in het bestandssysteem. In plaats van het IP-adres en poortnummer wordt het volledige pad van de socket gebruikt als unieke identificatie (bijv. /var/run/snmpd.sock). Unix-domein sockets hebben het voordeel van een aanzienlijk hogere doorvoer voor de IPC in vergelijking met verbindingen die de loopback- interface gebruiken.

Alternatieven voor sockets in communicatie tussen processen zijn buizen of gedeeld geheugen .

verhaal

Een centraal ontwerpprincipe van Unix is: Alles is een bestand. De vier meest gebruikte systeemaanroepen voor het werken met bestanden zijn: open() om te openen, read() om te lezen, write() om te schrijven en close() om te sluiten. Sockets vertegenwoordigen de implementatie van dit ontwerpprincipe.

De socket- API werd oorspronkelijk in 1983 ontwikkeld voor BSD Unix . De specificatie werd later opgenomen in de POSIX- standaard. Dit betekent dat het nu beschikbaar is op elk POSIX-compatibel besturingssysteem. Andere besturingssystemen zoals Microsoft Windows ( Winsock ) of OS / 2 hebben ook de socket-API overgenomen. Het wijdverbreide gebruik van sockets is niet alleen te danken aan het ontwerp van de sockets, maar ook aan de algemene beschikbaarheid van de broncode dankzij de BSD-licentie.

Gebruik in verschillende besturingssystemen

Unix- en Unix- achtige besturingssystemen (zoals Linux ) gebruiken heel vaak BSD-sockets voor netwerkcommunicatie. Voor lokale interprocescommunicatie gebruiken ze de hierboven beschreven Unix-domeinsockets (die onderdeel zijn van de POSIX- standaard) en waarmee processen op een eenvoudige manier met elkaar kunnen communiceren. Nadat de socket is geïnitialiseerd, kan de programmeur ermee werken als een bestand.

Windows gebruikt een zogenaamde Windows Sockets API (Winsock) die is gemodelleerd naar BSD-sockets.

Socket programmering

BSD Sockets-API

Zowel Unix Sockets als Windows Sockets zijn gebaseerd op de BSD Sockets API die in 1983 werd gepubliceerd. Belangrijke functies van deze API worden hier kort samengevat voor de volgende programmeervoorbeelden:

  • socket() Creëert een nieuwe socket van een bepaald type en wijst er systeembronnen aan toe. De functie retourneert een uniek nummer van het type integer voor identificatie.
  • bind() Bindt de socket aan socketadresinformatie, meestal een IP-adres en poort. Meestal gebruikt aan de serverkant.
  • listen() Zet een gebonden STREAM (TCP / IP)-socket in de luistermodus. Wordt gebruikt aan de serverkant.
  • connect() Maakt de adresinformatie (bijv. IP-adres en poort) van een andere socket bekend. Wijst een vrije lokale poort toe aan de socket. Bij een STREAM-socket wordt geprobeerd een nieuwe TCP/IP-verbinding tot stand te brengen. Wordt gebruikt aan de clientzijde.
  • accept() Accepteert een inkomende poging (verzoek) om een ​​nieuwe TCP / IP-verbinding tot stand te brengen met een externe client en, indien succesvol, maakt een nieuwe socket die is gekoppeld aan het adrespaar van de verbinding. Deze nieuw gemaakte socket wordt geretourneerd door de functie. Wordt gebruikt aan de serverkant.
  • send() en recv() , of write() en read() , of sendto() en recvfrom() Schrijft/lees data naar/van socket(s). Opmerking: Een enkele functieaanroep recv() garandeert niet de ontvangst van alle gegevens die door de afzender zijn verzonden met send() , vooral niet met STREAM-sockets.
  • close() Zorgt ervoor dat het besturingssysteem alle aan de socket toegewezen bronnen vrijgeeft. Als er een TCP/IP-socket is, wordt de verbinding verbroken.

C.

De van Linux afgeleide POSIX Sockets API is geschreven in C. Een voorbeeld van het tot stand brengen van een TCP-verbinding van een client naar een server:

 int sockfd = socket ( AF_INET , SOCK_STREAM , 0 ); // Maak een socket

struct sockaddr_in srv ;

memset ( & srv , 0 , sizeof ( struct sockaddr_in ));

srv . sin_familie = AF_INET ;
inet_pton ( AF_INET , "1.2.3.4" , & srv . sin_addr ); // Schrijf het IP-adres van de server in de structuur sockaddr_in
srv . sin_port = htons ( 1234 ); // Schrijf poort in netwerkbytevolgorde (Big Endian) in het veld sin_port

connect ( sockfd , ( struct sockaddr * ) & srv , sizeof ( struct sockaddr_in )); // Maak verbinding

// Vanaf nu kun je write () en read () gebruiken om van de socket te lezen en naar de socket te schrijven.

[...] // Gegevensuitwisseling

afsluiten ( sockfd , SHUT_WR ); // Stuur een EOF-byte zodat de server een retourwaarde van 0 ontvangt bij de volgende leesbewerking ()
                           // en kan de verbinding beëindigen

sluiten ( sockfd );

C #

 // stel IP-adres en poort in voor externe host
IPAddress IPAddress = IPAddress. Ontleden ( "192.168.xxx.yyy" );
IPEndPoint ipEndPoint = nieuw IPEndPoint ( ipAddress , 9999 );
Socket sok = nieuwe socket ( ipEndPoint . AddressFamily , SocketType . Stream , ProtocolType . Tcp );
// open stopcontact
sok . Verbinden ( ipEndPoint );
// controleer of het stopcontact is aangesloten
als ( sok . Verbonden )
{
	// eindeloze cirkel
	terwijl ( waar )
	{
		// stel ontvangstbuffer en lengte in, is buffer groot genoeg?
		byte [] bytesOntvangen = nieuwe byte [ 1024 ];
        int- bytes = 0 ;
        // bericht versturen
		byte [] msg1 = nieuwe byte [ 256 ];
		// ... stel je bytes, ASCII of wat dan ook in
        sok . Verzenden ( msg1 , msg1 . Lengte , SocketFlags . Geen );
		// bericht ontvangen
        bytes = sok . Ontvangen ( bytesOntvangen , bytesOntvangen . Lengte , SocketFlags . Geen );
	}
	sok . Afsluiten ( SocketShutdown . Beide );
    sok . Sluiten ();
}

Java

Java als platformonafhankelijke programmeertaal ondersteunt rechtstreeks socket-programmering in het java.net pakket. Dit toont aan dat het socketconcept onafhankelijk is van het besturingssysteem. De implementatie van de sockets voor de verschillende platformen (Linux, Windows, speciale systemen) vindt plaats in de klassenbibliotheek van de virtuele machine .

De klassen voor ServerSocket zijn Socket en ServerSocket . Het volgende korte voorbeeld toont het gebruik:

 ServerSocket serverSocket = nieuwe ServerSocket ( poort ); // Maak een server-socket met een specifiek poortnummer
 terwijl ( waar )
 {
   Socket clientSocket = serverSocket . accepteren (); // wacht op verzoeken
   InputStream input = clientSocket . getInputStream (); // Open het InputStream-object
   byte [] gegevens = nieuwe byte [ 1024 ] ; // declareren (maken) gegevensbuffer
   int aantalBytes = 0 ; // Variabele voor het aantal daadwerkelijk gelezen bytes
   aantalBytes = invoer . lezen ( gegevens ); // lees gegevens
   / *** leesgegevens verwerken *** /
   clientSocket . sluiten (); // sluit de verbinding
 }

De huidige Java-versie biedt ook de mogelijkheid om sockets te adresseren via de NewIO (nio) bibliotheek. De code is wat ingewikkelder, maar kan sneller worden uitgevoerd. Het multiplexen van meerdere sockets vindt plaats via een zogenaamde selector (vergelijkbaar met de Unix system call select ).

Haskell

De puur functionele Haskell- programmeertaal biedt een platformonafhankelijke mogelijkheid voor het gebruik van sockets via de Network . Het volgende voorbeeld bevat de volledige code voor een zeer eenvoudige server en een bijbehorende client . De client accepteert tekstregels van de standaardinvoer en stuurt deze via de netwerkaansluiting naar de server. Dit geeft op zijn beurt de tekstregels weer op de standaarduitvoer .

De hier getoonde server is eenvoudig omdat het z. B. zal waarschijnlijk geen veilige beëindiging toestaan. Een mogelijke oplossing wordt getoond in haskell.org [1] met behulp van software Transactional Memory (STM) .

Eenvoudige server

module Hoofd waar

import Control.Concurrent
importeer Control.Monad
importeer systeem.IO
netwerk importeren

hoofd : IO ()
main = withSocketsDo $ do
         theSocket <- listenOn ( Poortnummer 2048 )
         forever $ acceptConnectionAndFork theSocket echoServer

type MessageHandler = ( Handvat , String , Poortnummer ) -> IO ()

acceptConnectionAndFork : Socket -> MessageHandler -> IO ()
acceptConnectionAndFork theSocket- handler = do
  verbinding <- accepteer theSocket
  forkIO $ handler- verbinding
  terug ()

echoServer : MessageHandler
echoServer ( handle , hostnaam , poortnummer ) = do
  putStrLn $ "(" ++ hostnaam ++ ":" ++ toon poortnummer ++ "): Openen"
  c <- hGetContents- handvat
  mapM_ putStrLn [ "(" ++ hostnaam ++ ":" ++ toon poortnummer ++ "): Msg" ++ toon l | l <- regels c ]
  putStrLn $ "(" ++ hostnaam ++ ":" ++ toon poortnummer ++ "): Sluiten"

Eenvoudige klant

module Hoofd waar

netwerk importeren
importeer systeem.IO
import Control.Concurrent

hoofd :: IO ()
main = withSocketsDo $ do
         handle <- connectTo "localhost" ( Poortnummer 2048 )
         invoer <- getContents
         sequence_ [ do
                      hPutStrLn handvat l
                      hFlush handle |
                   l <- regels invoer ]
         hSluit handgreep

Robijn

In Ruby biedt de standaard socket ook een platformonafhankelijke interface voor het programmeren van TCP-sockets.

Een zeer eenvoudige server (met multithreading) die een tekst naar de client stuurt:

 require 'socket'

poort = 2048
server = TCPServer . nieuw ( poort )
lus doen
  cliënt = server . aanvaarden
  Draad . start ( klant ) doe | c |
    c . zet 'Hallo!'
    c . dichtbij
  einde
einde

Python 3

Een eenvoudig programma dat via de client berichten naar de server stuurt.

server

stopcontact importeren

# Server

host = "127.0.0.1" # IP-adres van de server
poort = 5000 # Poort gebruikt door de server
    
s = stopcontact . stopcontact ()
s . binden (( host , poort ))
s . lijsten ( 1 )

terwijl waar :

    klant , adres = s . accepteren ()
    print ( f "Verbonden met { addr } " )

    terwijl waar :
        
        gegevens = klant . recv ( 1024 )
        zo niet gegevens :
            pauze
        
        print ( f "Ontvangen van client: { data . decode () } " )

        cliënt . verzenden ( gegevens )

Cliënt

stopcontact importeren


host = "127.0.0.1" # IP-adres van de server
poort = 5000 # poort gebruikt door server

s = stopcontact . stopcontact ()     
s . verbinden (( host , poort ))

terwijl waar :
    msg = str ( invoer ( "Bericht ->" ))

    s . sendall (bericht coderen ())
    
    gegevens = s . recv ( 1024 )
    print ( f "Ontvangen van server: { data . decode () } " )

Node.js

In Node.js maakt de standaardmodule "net" het programmeren van TCP-sockets mogelijk.

 var net = vereisen ( 'net' );

var- server = net . createServer ( functie ( socket ) {
  stopcontact . schrijven ( 'Echoserver \ r \ n' );
  stopcontact . pijp ( mof );
});

server . luister ( 1337 , '127.0.0.1' );

web links

Individueel bewijs

  1. ^ Gelijktijdige demo's / Graceful exit op wiki.haskell.org