1 / 26 Netzwerk-Programmierung in C Oliver Bartels Fachbereich Informatik Universität Hamburg 2 Juli 2014
2 / 26 Inhaltsverzeichniss 1 IPv4 und IPv6 Wie werden Daten verschickt? 2 3 Verbindungsaufbau ohne GLib (nur libc) 4 GLib Verbindungsaufbau Serverseite Clientseite 5 Zusammenfassung 6 Literatur
IPv4 und IPv6 IP-Adressen intern sowie extern IPv4 (19216801) 2 32 Adressen 4 mal 8 Bit (1Byte) abgetrennt mit "" Erstes wirkliches Protokoll Problem: Zu wenig Adressen IPv6 (2001:db8:0:8d3:0:8a2e:70:7344) 2 128 mögliche Adressen 16Bit (2Byte) in hexadezimal mit ":"getrennt Problem: Nicht jeder hat bereits den Umstieg gemacht, im Heim- oder Firmennetzwerk ist IPv6 unnötig beide Protokolle müssen akzeptiert werden 3 / 26
Wie werden Daten verschickt? Speicherung der Daten im Netzwerk und im Rechner Big-Endian Speicherordnung mit großem Byte-Anteil zuerst logische Anordnung der Bytes Wird im Netzwerk immer verwendet b34f ist b3 4f im Speicher Little-Endian Speicherordnung mit kleinem Byte-Anteil zuerst umgekehrte Anordnung Wird bei Intel-Prozessoren verwendet b34f wird zu 4f b3 im Speicher Daten für Netzwerk einmal umschreiben 4 / 26
5 / 26 Wie werden Daten verschickt? Wie funktioniert das denn? IP-Adresse muss bekannt sein auch der Port ist wichtig (16Bit) Kommunikation mittels "file descriptor" file descriptor für Netzwerk über socket()
6 / 26 im allgemeinen 2 verschiedene Arten von : Stream und Datagram Stream sockets = 2-Wege Verbindung Datagram = verbindungslose
7 / 26 Stream TCP Transmission Control Protocol stellt eine Verbindung zwischen 2 Punkten her Wird fast ausschließlich als Transfer Protokoll genutzt 3-way handshake Prinzip zum Verbindungsaufbau HTTP HyperText Transfer Protocol setzt auf TCP auf Wird genutzt im Webseiten über das WWW zu laden
8 / 26 Datagram Socket UDP User Datagram Protocol verbindungsloses Netzwerkprotokoll Datenübertragung mittels Port unempfindlich und kein Datenschutz kleinere Datenpakete Verwendung bei einer DNS-Anfrage und zb VoIP
9 / 26 Veranschaulichung
10 / 26 Verbindungsaufbau ohne GLib (nur libc) Benötigte Libraries 1 # i n c l u d e < s y s / t y p e s h> 2 # i n c l u d e < netdb h> 3 # i n c l u d e < s y s / s o c k e t h> 4 # i n c l u d e < arpa / i n e t h> 5 # i n c l u d e < n e t i n e t / i n h>
11 / 26 Verbindungsaufbau ohne GLib (nur libc) Adressinformationen bekommen 1 s t r u c t a d d r i n f o 2 i n t a i _ f l a g s ; 3 i n t a i _ f a m i l y ; 4 i n t a i _ s o c k t y p e ; 5 i n t a i _ p r o t o c o l ; 6 s i z e _ t a i _ a d d r l e n ; 7 s t r u c t sockaddr * a i _ a d d r ; 8 char * ai_canonname ; 9 10 s t r u c t a d d r i n f o * a i _ n e x t ; 1 i n t g e t a d d r i n f o ( c o n s t char *node, 2 c o n s t char * s e r v i c e, 3 c o n s t s t r u c t a d d r i n f o * h i n t s, 4 s t r u c t a d d r i n f o ** r e s ) ;
12 / 26 Verbindungsaufbau ohne GLib (nur libc) socket() Welcher Sockettyp soll gewählt werden Entscheidung treffen ob Stream oder Datagram IPv4 oder IPv6 1 i n t s ; 2 s t r u c t a d d r i n f o h i n t s, * r e s ; 3 / / a u s f ü l l e n von " h i n t s " 4 g e t a d d r i n f o ( "www example com", " h t t p ", 5 &h i n t s, &r e s ) ; 6 / / e r r o r c h e c k i n g 7 / / nach g ü l t i g e n E i n t r ä g e n i n der l i n k e d l i s t 8 / / " r e s " suchen 9 s = s o c k e t ( res > a i _ f a m i l y, res >a i _ s o c k t y p e, 10 res > a i _ p r o t o c o l ) ;
13 / 26 Verbindungsaufbau ohne GLib (nur libc) bind() 1 i n t bind ( i n t sockfd, s t r u c t sockaddr *my_addr, 2 i n t a d d r l e n ) ; 1 memset(& h i n t s, 0, s i z e o f h i n t s ) ; 2 h i n t s a i _ f a m i l y = AF_UNSPEC ; 3 h i n t s a i _ s o c k t y p e = SOCK_STREAM ; 4 h i n t s a i _ f l a g s = AI_PASSIVE ; 5 6 g e t a d d r i n f o ( NULL, " 3490 ", &h i n t s, &r e s ) ; 7 8 s o c k f d = s o c k e t ( res > a i _ f a m i l y, 9 res >a i _ s o c k t y p e, res > a i _ p r o t o c o l ) ; 10 bind ( sockfd, res >ai_addr, res > a i _ a d d r l e n ) ;
14 / 26 Verbindungsaufbau ohne GLib (nur libc) connect() 1 i n t connect ( i n t sockfd, s t r u c t s o c k a d d r 2 * serv_addr, i n t a d d r l e n ) ; 1 memset(& h i n t s, 0, s i z e o f h i n t s ) ; 2 h i n t s a i _ f a m i l y = AF_UNSPEC ; 3 h i n t s a i _ s o c k t y p e = SOCK_STREAM ; 4 5 g e t a d d r i n f o ( "www example com", " 3490 ", &h i n t s, 6 &r e s ) ; 7 8 s o c k f d = s o c k e t ( res > a i _ f a m i l y, 9 res >a i _ s o c k t y p e, res > a i _ p r o t o c o l ) ; 10 11 connect ( sockfd, res >ai_addr, res > a i _ a d d r l e n ) ;
15 / 26 Verbindungsaufbau ohne GLib (nur libc) listen (), accept() listen() 1 i n t l i s t e n ( i n t sockfd, i n t b a c k l o g ) ; accept() 1 i n t a c c e p t ( i n t sockfd, s t r u c t sockaddr * addr, 2 s o c k l e n _ t * a d d r l e n ) ; 3 4 new_fd = a c c e p t ( sockfd, ( s t r u c t sockaddr * ) 5 &t h e i r _ a d d r, &a d d r _ s i z e ) ;
16 / 26 Verbindungsaufbau ohne GLib (nur libc) send (), recv() 1 i n t send ( i n t sockfd, c o n s t v o i d *msg, i n t len, 2 i n t f l a g s ) ; 1 char *msg = " Coding macht Spaß! " ; 2 i n t len, b y t e s _ s e n t ; 3 4 l e n = s t r l e n ( msg ) ; 5 b y t e s _ s e n t = send ( sockfd, msg, len, 0 ) ; 1 i n t r e c v ( i n t sockfd, v o i d * buf, i n t len, 2 i n t f l a g s ) ;
17 / 26 Verbindungsaufbau ohne GLib (nur libc) sendto (), recvfrom() für UDP sendto() 1 i n t sendto ( i n t sockfd, c o n s t v o i d *msg, 2 i n t len, unsigned i n t f l a g s, 3 c o n s t s t r u c t s o c k a d d r * to, 4 s o c k l e n _ t t o l e n ) ; recvfrom() 1 i n t recvfrom ( i n t sockfd, v o i d * buf, i n t len, 2 unsigned i n t f l a g s, 3 s t r u c t s o c k a d d r *from, 4 i n t * fromlen ) ;
Verbindungsaufbau ohne GLib (nur libc) close (), shutdown() close() 1 c l o s e ( s o c k f d ) ; shutdown() 1 i n t shutdown ( i n t sockfd, i n t how ) ; 18 / 26
19 / 26 Verbindungsaufbau ohne GLib (nur libc) Veranschaulichung
20 / 26 Serverseite GIO Serverseite 1 # i n c l u d e < g l i b h> 2 # i n c l u d e < g i o / g i o h> 3 4 g _ t y p e _ i n i t ( ) ; 5 6 G E r r o r * e r r o r = NULL ; 7 8 G S o c k e t S e r v i c e * s e r v i c e = g _ s o c k e t _ s e r v i c e _ n e w ( ) ; 9 10 g _ s o c k e t _ l i s t e n e r _ a d d _ i n e t _ p o r t ( 11 G S o c k e t L i s t e n e r * l i s t e n e r, 12 g u i n t 1 6 port, 13 GObject * s o u r c e _ o b j e c t, 14 G E r r o r ** e r r o r ) ;
21 / 26 Serverseite Serverseite 1 g _ s i g n a l _ c o n n e c t ( i n s t a n c e, d e t a i l e d _ s i g n a l, 2 c_handler, data ) 3 4 g _ s o c k e t _ s e r v i c e _ s t a r t ( s e r v i c e ) ; 5 6 gboolean 7 i n c o m i n g _ c a l l b a c k ( G S o c k e t S e r v i c e * s e r v i c e, 8 GSocketConnection * connection, 9 GObject * s o u r c e _ o b j e c t, 10 g p o i n t e r u s e r _ d a t a )
22 / 26 Clientseite GIO Clientseite 1 # i n c l u d e < g l i b h> 2 # i n c l u d e < g i o / g i o h> 3 4 g _ t y p e _ i n i t ( ) ; 5 6 G E r r o r * e r r o r = NULL ; 7 8 GSocketConnection * c o n n e c t i o n = NULL ; 9 10 G S o c k e t C l i e n t * c l i e n t = g _ s o c k e t _ c l i e n t _ n e w ( ) ;
23 / 26 Clientseite 1 GSocketConnection * 2 g _ s o c k e t _ c l i e n t _ c o n n e c t _ t o _ h o s t ( 3 G S o c k e t C l i e n t * c l i e n t, 4 c o n s t g c h a r * host_and_port, 5 g u i n t 1 6 d e f a u l t _ p o r t, 6 G C a n c e l l a b l e * c a n c e l l a b l e, 7 G E r r o r ** e r r o r ) ; 8 9 GInputStream * 10 g _ i o _ s t r e a m _ g e t _ i n p u t _ s t r e a m ( 11 GIOStream * stream ) ; 12 13 GOutputStream * 14 g _ i o _ s t r e a m _ g e t _ o u t p u t _ s t r e a m ( 15 GIOStream * stream ) ;
24 / 26 Clientseite verschiedene Operationen möglich wie zb 1 g s s i z e 2 g _ o u t p u t _ s t r e a m _ w r i t e ( GOutputStream * stream, 3 c o n s t v o i d * b u f f e r, 4 g s i z e count, 5 G C a n c e l l a b l e * c a n c e l l a b l e, 6 G E r r o r ** e r r o r ) ; Fehler überprüfung 1 i f ( e r r o r!= NULL ) 2 { 3 g _ e r r o r ( e r r o r >message ) ; 4 }
25 / 26 Zusammenfassung Verbindungsart wählen (Stream oder Datagram socket) TCP ist eine gesicherte Verbindung, UDP ist schneller, aber nicht so sicher getaddrinfo() vieles ausfüllen lassen bind() für Server um Port mit Programm zu verknüpfen, bei Client nicht nötig schneller und einfacher geht es mit der GLib Umfangreiches Thema, es wurde nicht alles behandelt
26 / 26 Literaturverzeichnis http://dewikipediaorg/wiki/transmission_control_protocol http://dewikipediaorg/wiki/ipv4 http://dewikipediaorg/wiki/ipv6 https://developergnomeorg/gio/stable/ http://linuxdienet/man/3/getaddrinfo http://stackoverflowcom/questions/9513327/gio-socketserver-client-example http://beejus/guide/bgnet/output/html/multipage/indexhtml