CS:APP-ch11 Network Programming
11.1 The Client-Server Programming Model
4 steps of client-server transaction
11.2 Networks
a hierarchical system that is organized by geographical proximity.
lowest level: LAN (Ethernet)
higher level: WAN
internet
consist of different LANs and WANs with radically different and incompatible technologies.
a layer of protocol software running on each host and router that smoothes out the differences between the different networks. (network layer)
step 5 : router strips off the old LAN1 frame header and prepends a new LAN2 frame header.
11.3 The Global IP Internet
11.3.1 IP Addresses
an unsigned 32-bit integer
1 2 3 4 | /* Internet address structure */ struct in_addr { unsigned int s_addr; /* Network byte order (big-endian) */ }; |
Addresses in IP address structures are always stored in (big-endian) network byte order, even if the host byte order is little-endian.
convert between network and host byte order
1 2 3 4 5 6 7 | unsigned long int htonl ( unsigned long int hostlong ); unsigned short int htons ( unsigned short int hostshort ); // Returns : value in network byte order unsigned long int ntohl ( unsigned long int netlong ); unsigned short int ntohs ( unsigned short int netshort ); // Returns : value in host byte order |
convert between IP addresses and dotted- decimal strings
1 2 3 | int inet_pton ( AF_INET, const char *src, void *dst );// dst = struct in_addr const char *inet_ntop( AF_INET, const void *src, char *dst, socklen_t size ); |
11.3.2 Internet Domain names
nslookup
11.3.3 Internet Connections
socket address: ip addr : port
11.4 The Sockets Interface
socket address structure
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* IP socket address structure */ struct sockaddr_in { uint16_t sin_family; /* Protocol family (always AF_INET) */ uint16_t sin_port; /* Port number in network byte order */ struct in_addr sin_addr; /* IP address in network byte order */ unsigned char sin_zero[ 8 ]; /* Pad to sizeof ( struct sockaddr ) */ }; /* Generic socket address structure (for connect, bind, and accept) */ struct sockaddr { uint16_t sa_family; /* Protocol family */ char sa_data[ 14 ]; /* Address data. */ }; |
socket
1 2 3 4 | int socket( int domain, int type, int protocol ); |
connect
1
| int connect( int clientfd, const struct sockaddr *addr, socklen_t addrlen );
|
bind: associate server’s socket address with socketfd
1
| int bind( int sockfd, const struct sockaddr *addr, socklen_t addrlen );
|
listen: convert to listening socket that accept connections
1
| int listen( int sockfd, int backlog );
|
accept
1
| int accept ( int listenfd, struct sockaddr *addr, int *addrlen );
|
struct addrinfo
1 2 3 4 5 6 7 8 9 10 | struct addrinfo { int ai_flags; /*hints argument flags*/ int ai_family; /*first arg to socket fun*/ int ai_socktype; /*second arg*/ int ai_protocol; /*third arg*/ char *ai_canonname; /*canonical host name*/ size_t ai_addrlen; /*size of ai_addr struct*/ struct sockaddr *ai_addr; /*ptr to socket address structure*/ struct adrinfo *ai_netx; /*ptr to next item in linked list*/ }; |
convert between binary socket address structures and hostname strings
getaddrinfo
1 2 3 4 5 6 7 8 9 | int getaddrinfo( const char *host, const char *service, const struct addrinfo *hints, struct addrinfo **result ); void freeaddrinfo( struct addrinfo *result ); const char *gai_strerror( int errcode ); |
getnameinfo
1 2 3 | int getnameinfo( const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *service, size_t servlen, int flags ); |
usage: combine all
open_clientfd ( getaddrinfo, socket, connect, freeaddrinfo )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | /* * open_clientfd - Open connection to server at <hostname, port> and * return a socket descriptor ready for reading and writing. This * function is reentrant and protocol-independent. * * On error, returns: * -2 for getaddrinfo error * -1 with errno set for other errors. */ /* $begin open_clientfd */ int open_clientfd ( char *hostname, char *port ) { int clientfd, rc; struct addrinfo hints, *listp, *p; /* Get a list of potential server addresses */ memset ( &hints, 0, sizeof ( struct addrinfo ) ); hints.ai_socktype = SOCK_STREAM; /* Open a connection */ hints.ai_flags = AI_NUMERICSERV; /* ... using a numeric port arg. */ hints.ai_flags |= AI_ADDRCONFIG; /* Recommended for connections */ if ( ( rc = getaddrinfo ( hostname, port, &hints, &listp ) ) != 0 ) { fprintf ( stderr, "getaddrinfo failed (%s:%s): %s\n", hostname, port, gai_strerror ( rc ) ); return -2; } /* Walk the list for one that we can successfully connect to */ for ( p = listp; p; p = p->ai_next ) { /* Create a socket descriptor */ if ( ( clientfd = socket ( p->ai_family, p->ai_socktype, p->ai_protocol ) ) < 0 ) continue; /* Socket failed, try the next */ /* Connect to the server */ if ( connect ( clientfd, p->ai_addr, p->ai_addrlen ) != -1 ) break; /* Success */ if ( close ( clientfd ) < 0 ) { /* Connect failed, try another */ // line:netp:openclientfd:closefd fprintf ( stderr, "open_clientfd: close failed: %s\n", strerror ( errno ) ); return -1; } } /* Clean up */ freeaddrinfo ( listp ); if ( !p ) /* All connects failed */ return -1; else /* The last connect succeeded */ return clientfd; } /* $end open_clientfd */ |
open_listenfd (getaddrinfo, socket, bind, listen, freeaddrinfo)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | /* * open_listenfd - Open and return a listening socket on port. This * function is reentrant and protocol-independent. * * On error, returns: * -2 for getaddrinfo error * -1 with errno set for other errors. */ /* $begin open_listenfd */ int open_listenfd ( char *port ) { struct addrinfo hints, *listp, *p; int listenfd, rc, optval = 1; /* Get a list of potential server addresses */ memset ( &hints, 0, sizeof ( struct addrinfo ) ); hints.ai_socktype = SOCK_STREAM; /* Accept connections */ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG; /* ... on any IP address */ hints.ai_flags |= AI_NUMERICSERV; /* ... using port number */ if ( ( rc = getaddrinfo ( NULL, port, &hints, &listp ) ) != 0 ) { fprintf ( stderr, "getaddrinfo failed (port %s): %s\n", port, gai_strerror ( rc ) ); return -2; } /* Walk the list for one that we can bind to */ for ( p = listp; p; p = p->ai_next ) { /* Create a socket descriptor */ if ( ( listenfd = socket ( p->ai_family, p->ai_socktype, p->ai_protocol ) ) < 0 ) continue; /* Socket failed, try the next */ /* Eliminates "Address already in use" error from bind */ setsockopt ( listenfd, SOL_SOCKET, SO_REUSEADDR, // line:netp:csapp:setsockopt (const void *)&optval, sizeof ( int ) ); /* Bind the descriptor to the address */ if ( bind ( listenfd, p->ai_addr, p->ai_addrlen ) == 0 ) break; /* Success */ if ( close ( listenfd ) < 0 ) { /* Bind failed, try the next */ fprintf ( stderr, "open_listenfd close failed: %s\n", strerror ( errno ) ); return -1; } } /* Clean up */ freeaddrinfo ( listp ); if ( !p ) /* No address worked */ return -1; /* Make it a listening socket ready to accept connection requests */ if ( listen ( listenfd, LISTENQ ) < 0 ) { close ( listenfd ); return -1; } return listenfd; } /* $end open_listenfd */ |
client routine (close)
1 2 3 4 5 6 7 8 9 | clientfd = Open_clientfd ( host, port ); Rio_readinitb ( &rio, clientfd ); while ( Fgets ( buf, MAXLINE, stdin ) != NULL ) { // read from std input Rio_writen ( clientfd, buf, strlen ( buf ) ); // write to server Rio_readlineb ( &rio, buf, MAXLINE ); // read from server Fputs ( buf, stdout ); } Close ( clientfd ); exit ( 0 ); |
server routine (accept, close)
1 2 3 4 5 6 7 8 9 10 | listenfd = Open_listenfd ( argv[ 1 ] ); while ( 1 ) { // protocol independent socket address structure rather than sockaddr_in clientlen = sizeof ( struct sockaddr_storage ); connfd = Accept ( listenfd, (SA *)&clientaddr, &clientlen ); // SA = sockaddr echo ( connfd ); Close ( connfd ); } exit ( 0 ); |
11.5 Web Servers
Web clients and servers interact using a text-based application-level protocol known as HTTP (Hypertext Transfer Protocol).
web content: static & dynamic, disk file & output of an executable file
URL: server : port / filename ? arg1 & arg2
http://bluefish.ics.cs.cmu.edu:8000/cgi-bin/adder?15000&213
http transaction
- use telnet to conduce transactions with any web server
http request: method URI version
GET /index.html HTTP/1.0
http response: version status-code status-message
- HTTP/1.0 404 Not found
dynamic content
- fork and execute a child process , redirect stdout to client