710 likes | 947 Views
Network Application Programming. Introduction: issues Sockets: programming and implementation Other API’s: winsock java transport layer interface (TLI) Novell netware API Reading: Tannenbaum, page 486-487 ftp://gaia.cs.umass.edu/cs653/sock.ps.
E N D
Network Application Programming Introduction: issues Sockets: programming and implementation Other API’s: • winsock • java • transport layer interface (TLI) • Novell netware API Reading: Tannenbaum, page 486-487 ftp://gaia.cs.umass.edu/cs653/sock.ps
The Application Programming Interface: API • API: the programming model, application callable services, interfaces, and abstractions provided by the network (i.e., lower layers) to the application. • does an API provide for: • naming and service location: must application know precise location (e.g., host address and port) of service? Can services be requested by name? Can servers registers services? • connection management. must applications do low-level handshaking required to setup/teardown connection?
The API (continued) Does an API provide for: • message transfer • application-selectable data transfer services: best-effortversus reliable? • message priorities? • multi-site atomic actions? • structured versus byte-stream communication? • communication flexibility • can application select and/or modify protocol stacks (statically or dynamically)? • Quality of Service specification • can application specify QoS requirements to network?
The SOCKET API • introduced in 1981 BSD 4.1 UNIX • a host-local, application created/owned, OS-controlled interface into which application process can both send and receive messages to/from another (remote or local) application process
The SOCKET API (cont) • two sockets on separate hosts ``connected'' by OS socket management routines. Application only sees local socket. • sockets explicitly created, used, released by applications • based on client/server paradigm • two types of transport service via socket API: • unreliable datagram • reliable, stream-oriented • presentation, session layers missing in UNIX networking (an application concern!).
Sockets: conceptual view • each socket has separate send/receive buffers, port id, parameters (application queryable and setable). • socket operations implemented as system calls into OS • user/kernel boundary crossed: overhead
Sockets: conceptual view User space USER APP. msgsend() bind() msgsrecv() getsockopt() setsocketopt() buffered data yet to send SOCKET LAYER buffered data yet to be sent socket parameters Operating system port # TRANSPORTLAYER ?
Connectionless Service • datagram service:underlying transport protocols do not guarantee delivery • no explicit identification of who is server, who is client • if initiating contact with other side, need to know • IP address • port number of process waiting to be contacted. • if waiting for contact from other side, need to declare • port number at which waiting for other side
CLIENT 1. create transport endpoint: socket() SERVER 1.create transport endpoint: socket() 2. assign transport endpoint address: (optional) bind() 2. assign transport endpoint an address: bind() 3. determine address of server 4. send msg: sendto() 3. wait for pkt to arrive: recvfrom() 5. wait for pkt to arrive: recvfrom() 4. send reply (if any): sendto() 6. Release transport endpoint: close() 5. release transport endpoint: close()
Creating a socket • same endpoint (socket) used to send/receive data • no a priori association of socket with network • must specify transport protocol family, and specific transport-level service to be used with socket:
Creating a socket (cont.) int socket ( int family, int service, int protocol) • family is symbolic name of protocol family • service is symbolic name of service type • protocol allows further specification of raw socket. For us, this will be 0. • return code from socket() is a socket descriptor, used in all remaining socket-related system calls Example: #include <sys/types.h> #include<sys/ socket.h> int sockfd; if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { /* handle error */ }
Internet addressing • each Internet host has one or more globally-unique 32-bit IP addresses • host may have two or more addresses • address associated with each interface card • dotted decimal notation: • 4 decimal integers, each specifying one byte of IP address:
Internet addressing • library procedure inet_addr() converts dotted-decimal address string to a 32-bit address • library procedure gethostbyname() converts textual name to dotted-decimal.
The Internet Domain System Structure • hierarchical administering of names • e.g.: gaia.cs.umass.edu • leftmost name is typically a host name (has an IP address) • next leftmost name is organization administering that host (e.g., UMass CS Dept.) • next leftmost name is organization administering all of subnames to the left (e.g., UMass administers cs, ecs, ucs domains)
rightmost (highest) domain an organization, structure, country
DNS: Internet Domain Name System • a distributed database used by TCP/IP applications to map to/from hostnames from/to IP addresses • name servers : • user-level library routines gethostbyname() and gethostbyaddress() contact local nameserver via port 53 • name server returns IP address of requested hostname
DNS: non-local names finding non-local names • no single name server has complete info • if local name server can't resolve address, contacts root name server: • 9 redundant root nameservers world-wide • each has addresses of names servers for all level-two name servers (e.g., umass.edu, ibm.com) • contacted root server returns IP address of name server resolver should contact • contacted level-two name server may itself return a pointer to another name server • name resolution an iterative process of following name server pointers • DNS protocol specifies packet formats for exchanges with DNS servers
Assigning socket a network address: bind() • each socket must be associated with a local, host-unique 16-bit port number. • need to associate socket with globally unique network address (host address and port) • OS knows that incoming messages addressed to this host address and port to be delivered (demultiplexed to) to this socket • a return address for outgoing messages
Socket addressing: predefined address structures specifying socket addresses: certain data structures predefined for you: struct sockaddr_in { /* INET socket addr info */ short sin_family; /* set me to AF_INET */ u_short sin_port; /* 16 bit number, nbo */ struct in_addr sin_addr; /* 32 bit host address */ char sin_zero[8]; /* not used */ }; struct in_addr { u_long s_addr; /* 32 bit host addr.,nbo */};
The bind() system call int bind ( int sockfd, struct sockaddr *myaddr, int addresslen) • sockfdis the variable assigned socket() return value. • *myaddr: address of sockaddr_in structure holding local address info. Must be cast to type sockaddr. • addresslen is the size of the address structure error return indicates port number already in use, out-of-range
The bind() system call (cont) #include <sys/types.h> #include <sys/socket.h> #include "inet.h” int sockfd; struct sockaddr_in myaddr; if ( (sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { /* handle error */ } myaddr.sin_family = AF_INET; myaddr.sin_port = htons(5100); /* > 5000 myaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* INADDR lets OS determine hostid */ if ( bind(sockfd, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) { /* handle error */ }
Example: connectionless server 1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/socket.h> 4 #include <netinet/in.h> 5 #include <arpa/inet.h> 6 #include <errno.h> 7 #define MY_PORT_ID 6090 /* a number > 5000 */ 8 9 main() 10 { 11 int sockid, nread, addrlen; 12 struct sockaddr_in my_addr, client_addr; 13 char msg[50]; 14
15 printf("Server: creating socket\n"); 16 if ( (sockid = socket (AF_INET, SOCK_DGRAM, 0)) < 0){ 17 printf("Server: socket error: %d\n",errno); 18 exit(0); 19 } 20 printf("Server: binding my local socket\n"); 21 bzero((char *) &my_addr, sizeof(my_addr)); 22 my_addr.sin_family = AF_INET; 23 my_addr.sin_addr.s_addr = htons(INADDR_ANY); 24 my_addr.sin_port = htons(MY_PORT_ID);
Example: connectionless server (cont) 25 if ( (bind(sockid, (struct sockaddr *) &my_addr, 26 sizeof(my_addr)) < 0) ){ 27 printf("Server: bind fail: %d\n",errno); 28 exit(0); 29 } 30 printf("Server: starting blocking message read\n"); 31 nread = recvfrom(sockid,msg,11,0, 32 (struct sockaddr *) &client_addr, &addrlen); 33 printf("Server: return code from read is %d\n",nread); 34 if (nread >0) printf("Server: message is: %.11s\n",msg); 35 close(sockid); 36 }
Example: connectionless client 1 #include <stdio.h> 2 #include <sys/types.h> 3 #include <sys/socket.h> 4 #include <netinet/in.h> 5 #include <arpa/inet.h> 6 #include <errno.h> 7 #define MY_PORT_ID 6089 8 #define SERVER_PORT_ID 6090 9 #define SERV_HOST_ADDR "128.119.40.186" 10 11 main() 12 { 13 int sockid, retcode; 14 struct sockaddr_in my_addr, server_addr; 15 char msg[12];
16 17 printf("Client: creating socket\n"); 18 if ((sockid = socket(AF_INET, SOCK_DGRAM, 0)) < 0){ 19 printf("Client: socket failed: %d\n",errno); 20 exit(0); 21 } 22 23 printf("Client: binding my local socket\n"); 24 bzero((char *) &my_addr, sizeof(my_addr)); 25 my_addr.sin_family = AF_INET; 26 my_addr.sin_addr.s_addr = htonl(INADDR_ANY); 27 my_addr.sin_port = htons(MY_PORT_ID); 28 if ( ( bind(sockid, (struct sockaddr *) &my_addr, 29 sizeof(my_addr)) < 0) ){ 30 printf("Client: bind fail: %d\n",errno); 31 exit(0); 32 } 33
30 printf("Client: creating addr structure for server\n"); 31 bzero((char *) &server_addr, sizeof(server_addr)); 32 server_addr.sin_family = AF_INET; 33 server_addr.sin_addr.s_addr = inet_addr(SERV_HOST_ADDR); 34 server_addr.sin_port = htons(SERVER_PORT_ID); 35 36 printf("Client: initializing message and sending\n"); 37 sprintf(msg, "Hello world"); 38 retcode = sendto(sockid,msg,12,0,(struct sockaddr *)&server_addr, sizeof(server_addr)); 39 if (retcode <= -1){ 40 printf("client: sendto failed: %d\n",errno); 41 exit(0); 42 } 43 44 /* close socket */ 45 close(sockid); 46 }
Example: execution trace > cc udpserver.c; mv a.out udpserver > cc udpclient.c; mv a.out udpclient > udpserver & [1] 20837
> Server: creating socket Server: binding my local socket Server: starting blocking message read > udpclient Client: creating socket Client: binding my local socket Client: creating addr structure for server Client: initializing message and sending Server: return code from read is 11 Server: message is: Hello world [1] Done udpserver
SERVER CLIENT create transport endpoint:socket() for incoming requests create transport endpoint: socket() assign trasnport endpoint an address (optional) :bind() assign address to transport endpoint:bind() announce willing to accept connections: listen() determine addr. of server msg exchange and synch. connect to server via socket: connect() block/wait for incoming conn. req.: accept()(new socket created on return) request send msg: sendto() wait for pkt:recvfrom() reply wait for reply:recvfrom() send reply (if any):sendto() release transport endpoint:close() release transport endpoint:close()
Connection-oriented service • client/server handshaking: • client must explicitly connect to server before sending or receiving data • client will not pass connect() until server accepts client • server must explicitly accept client before sending or receiving data • server will not pass accept() until client connect()'s • connection-oriented service: underlying transport service is reliable, stream-oriented.
Client-to-server connection: connect() • client uses connect() to request connect to server and communication via socket • underlying transport protocol (e.g. TCP) begins connection setup protocol implementing client/server handshake • connect() returns when server explicitly accepts connection, or timeout (no server response) • typically used with reliable transport protocols, but also with datagrams
Client-to-server connection: connect() int connect ( int sockfd, struct sockaddr *toaddrptr, int addresslen) • sockfd:variable assigned socket() return value. Process accepts incoming connections on this socket id. • *toaddrptr is address of sockaddr_in structure holding server address info. Must be cast to type sockaddr. • addresslen is the size of address structure
The listen() system call • used by connection-oriented server • let network/OS know server will accept connection requests • does not block and does not wait for request! • int listen ( int sockfd, int maxwaiting) • sockfd:variable assigned socket() return value. Process accepts incoming connections on this socket id. • maxwaiting: maximum number of connection requests that can be queued, waiting for server to do an accept(). Typical value is 5.
Server-to-client connection: accept() • done by server, after listen(). • server will accept() connection request via specified socket, and return newly created socket for use in communicating back to accept()'ed client. • server has one socket for accepting incoming connection requests • creates other (new) sockets for communication with clients • server can not selectively accept() connection requests • typically handled FCFS.
accept(), cont int accept ( int sockfd, struct sockaddr *fromaddrptr, int *addresslen) • sockfd is variable assigned socket() return value. • *fromaddrptr is address of sockaddr_in structure containing address info of socket that sent this data. A returned value. • addresslen is size of address structure. A value-result argument (set before call, reset during call).
accept(), cont struct sockaddr_in other_app_addr; int sockid, newsockid, addrsize; … addrsize = sizesizeof(other_app_addr)); newsockid = accept(sockfd, (struct sockaddr *) &other_app_addr, &addrsize); /* newsockid to communicate with client, sockid to accept more connections */
A Simple Timing Application: 1 Client: • connect to server • send server client local time • read back server's local time Server: • receive connections from clients • print out client's local time • send client server's local time
A Simple Timing Application: client code 1 #include <sys/types.h> 2 #include <sys/socket.h> 3 #include <netinet/in.h> 4 #include <arpa/inet.h> 5 #include <time.h> 6 #include <errno.h> 7 #define SERV_HOST_ADDR "128.119.40.186" /* Don's host machine */ 8 main() 9 { 10 int sockid; 11 struct sockaddr_in ssock_addr; 12 struct timeval tp; 13 struct timezone tzp; 14
15 /* create a socket */ 16 if ( (sockid = socket(AF_INET, SOCK_STREAM, 0)) < 0){ 17 printf("error creating client socket,error%d\n",errno); 18 exit(0); 19 } 20 21 printf("Client: creating addr structure for server\n"); 22 bzero((char *) &server_addr, sizeof(server_addr)); 23 server_addr.sin_family = AF_INET; 24 server_addr.sin_addr.s_addr = inet_addr(SERV_HOST_ADDR); 25 server_addr.sin_port = htons(SERVER_PORT_ID); 26 if (connect(sockid, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0){ 27 printf("error connecting to server, error: %d\n",errno); 28 exit(0); 29 }
30 /* send time of day */ 31 gettimeofday(&tp,&tzp); 32 /* convert from host byte order to network byte order */ 33 printf("client: local time is %ld\n",tp.tv_sec); 34 tp.tv_sec = htonl(tp.tv_sec); 35 tp.tv_usec = htonl(tp.tv_usec); 38 /* send time of day to other side */ 39 write(sockid, &tp, sizeof(tp)); 40 /* get time of day back fro other side and display */ 41 if ( (read(sockid, &tp, sizeof(tp))) < 0){ 42 printf("error reading new socket\n"); 43 exit(0); 44 } 45
46 /* convert from network byte order to host byte order */ 47 tp.tv_sec = ntohl(tp.tv_sec); 48 tp.tv_usec = ntohl(tp.tv_usec); 49 printf("client: remote time is %ld\n",tp.tv_sec); 50 close(sockid); 51 }
Simple Timing Application: server code 1 #include <stdio.h>2 #include <sys/types.h>3 #include <sys/socket.h>4 #include <netinet/in.h>5 #include <arpa/inet.h>6 #include <time.h>7 #include <errno.h>8 #define MY_PORT_ID 6090 /* a number > 5000 */910 main()11 {12 int sockid, newsockid, i,j;13 struct sockaddr_in ssock_addr;14 struct timeval tp;15 struct timezone tzp;16
17 /* create a socket * 18 if ( (sockid = socket (AF_INET, SOCK_STREAM, 0)) < 0) 19 { printf("error creating socket, error: %d\n",errno); exit(0);} 20 /* do a man on errno to get error information */ 21 /* name the socket using wildcards */ 22 bzero((char *) &ssock_addr, sizeof(ssock_addr));\ 23 ssock_addr.sin_family = AF_INET;\ 24 ssock_addr.sin_addr.s_addr = htonl(INADDR_ANY); 25 ssock_addr.sin_port = htons(MY_PORT_ID); 26 /* bind the socket to port address */ 27 if ( ( bind(sockid, (struct sockaddr *) &ssock_addr, sizeof(ssock_addr)) < 0) ) 28 { printf("error binding socket, error: %d\n",errno); exit(0); } 29 /* start accepting connections */ 30 if ( listen (sockid, 5) < 0) 31 { printf("error listening: %d\n",errno); exit(0); } 32
33 for (i=1; i<=50000 ;i++) { 34 /* accept a connection */ 35 newsockid = accept(sockid, (struct sockaddr *)0, (int *)0); 36 if (newsockid < 0) 37 { printf("error accepting socket, error: %d\n",errno); exit(0); } 38 /* read remote time of day from socket */ 39 if ( (read(newsockid, &tp, sizeof(tp))) < 0) 40 { printf("error reading new socket\n"); exit(0); } 41 /* convert from network byte order to host byte order */ 42 tp.tv_sec = ntohl(tp.tv_sec); 43 tp.tv_usec = ntohl(tp.tv_usec); 44 printf("server: remote time is %ld\n",tp.tv_sec); 45
46 /* get local time of day and send to client*/ 47 for (j=0; j<1000000; j++) 48 ; /* delay */ 49 gettimeofday(&tp,&tzp); 50 /* convert from host byte order to network byte order */ 51 printf("server: local time is %ld\n",tp.tv_sec); 52 tp.tv_sec = htonl(tp.tv_sec); 53 tp.tv_usec = htonl(tp.tv_usec); 54 write(newsockid, &tp, sizeof(tp)); 55 close(newsockid); 56 } 57 close(sockid); 58 }