800 likes | 1.01k Views
Network Application Programming. Introduction: issues Sockets: programming and implementation Other API’s: winsock java transport layer interface (TLI) Novell netware API. The Application Programming Interface: API.
E N D
Network Application Programming Introduction: issues Sockets: programming and implementation Other API’s: • winsock • java • transport layer interface (TLI) • Novell netware API Socket API2: Application Layer
The Application Programming Interface: API • Definition : an API is 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? Socket API2: Application Layer
The API (continued) Does an API provide for: • Message transfer • application-selectable data transfer services: best-effort versus reliable? • message priorities? • multi-site atomic actions? • e.g. deliver everywhere or nowhere; all at same time;... • 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? Socket API2: Application Layer
Sockets and UNIX I/O • Standards do not specify how application will interface with the protocols. • interface architecture is not standardized, its design is outside the scope of the protocol suite • most often interface details depend on the operating system in use • UNIX development (60’s and 70’s) has each application program execute as a user level process. • application program interacts with OS via a system call • system calls behave like other procedure calls -i.e. take arguments and return one or more results • arguments can be values or pointers to objects ( e.g.a buffer to be read or filled with characters) • UNIX I/O follows paradigm of open-read-write-close ( from MULTICS and earlier OS ) Socket API2: Application Layer
UNIX I/O • Before a process performs I/O operations - • it calls open to specify the file or device to be used and obtains permission • the call to open returns a small integer file descriptor the process uses when performing the I/O operations on the opened file or device • once opened, user makes one or more calls to read or write to transfer data • both read and write take 3 arguments that specify : • file descriptor to use • address of a buffer • number of bytes to transfer • after all transfer operations are completed, the user calls close to inform the OS it is finished with the object Socket API2: Application Layer
BSD UNIX and Network Protocols • BSD developers decided that the complexity of network protocols required more power and flexibility than the early I/O models provided • programmers needed to create both server code that waits passively as well as code that forms connections actively • applications sending datagrams may wish to specify destination address along with each datagram rather than binding destinations at the time they call open • To deal with these observations, they chose to abandon the traditional I/O paradigm and to add several new OS calls and new library routines to BSD UNIX • this increased the Unix I/O complexity • The basis for network I/O in BSD UNIX is centered on the abstraction known as the socket • introduced in 1981 BSD 4.1 UNIX ( Bill Joy, founder of SUN) Socket API2: Application Layer
The SOCKET API • Definition :a socket is a host-local, application created/owned, OS-controlled interface into which the application process can both send and receive messages to/from another (remote or local) application process • two sockets on separate hosts ``connected'' by OS socket management routines. Application only sees local socket. Socket API2: Application Layer
Sockets • think of a socket as a generalization of the UNIX file access mechanism • application programs request the OS to create a socket when one is needed • system returns a small integer that applications use to reference the newly created socket • in this case however, the OS binds a file descriptor to a specific file or device when the application calls open but it can do so without binding them to specific destination addresses • the application chooses the destination address each time it uses the socket • e.g. when sending datagrams • or it can choose to bind the destination address to the socket and avoid necessity of repeatedly specifying address • e.g. a TCP connection • can also be used for traditional read - write operations Socket API2: Application Layer
The SOCKET API (cont) • 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!). Socket API2: Application Layer
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 Socket API2: Application Layer
Create an endpoint for communication #include <sys/socket.h> #include <netinet/in.h> int socket (af, type, protocol) int af; int type; int protocol; where: af Address family (domain) type Type of service desired protocol Optional protocol id (usually 0) possible family values AF_UNIX local host domain AF_INET internet domain possible service type values SOCK_STREAM virtual circuit socket SOCK_DGRAM datagram socket SOCK_RAW access to internal network returns: channel number on success, or -1 Socket API2: Application Layer
Create a pair of connected UNIX domain sockets #include <sys/socket.h> int socketpair (af, type, protocol, sv) int d; int type; int protocol; int sv[2]; where: af Address family (domain)of the socket, AF_UNIX type Type of service, SOCK_STREAM/ SOCK_DGRAM protocol Protocol of interest, 0 for default sv Buffer in which to return descriptors Description The socket pair call is used in the UNIX domain only to create a connected pair of sockets in the style of the pipe() call. A creator would typically fork() a child (or children) and use the channel inheritance of the offspring for full duplex IPC. Unlike a pipe, both channel descriptors are open for reading and writing with no possible crosstalk. returns: 0 on success, or -1 Socket API2: Application Layer
Initiate a connection on a socket #include <sys/socket.h> #include <netinet/in.h> #include <sys/un.h> int connect (s, name, namelen) int s; const struct sockaddr * name; int namelen; where: s The file descriptor of a socket to connect name Name of peer or listening socket through which the connection will be made namelen Length of name (bytes) possible name address formats struct sockaddr_un{ short sun_family; /* AF_UNIX */ char sun_path[109]; /* UNIX file path */ }; struct sockaddr_in{ short sin_family; /* AF_INET */ u_short sin_port; /* port number */ struct in_addr sin_addr; /* inet addr */ char sin_zero[8]; } returns: 0 on success, or -1 Socket API2: Application Layer
Sockets: conceptual view Socket API2: Application Layer
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 you are waiting for other side to send data Socket API2: Application Layer
Creating a socket • Socket system call creates sockets on demand • Takes 3 integer arguments and returns an integer result : • result = socket ( pf, type, protocol ) • pf argument- specifies the protocol family to be used with the socket • i.e how to interpret addresses when supplied • type argument specifies the type of communication desired • protocol argument allows further flexibility Socket API2: Application Layer
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: Socket API2: Application Layer
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 */ } Socket API2: Application Layer
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: host name cs.uml.edu • 32-bit address 10000001 00111111 00000001 00000111 • dotted decimal 129.63.1.6 • library procedure inet_addr() converts dotted-decimal address string to a 32-bit address • library procedure gethostbyname() converts textual name to 32 bit address. Socket API2: Application Layer
The Internet Domain System Structure • hierarchical administering of names • e.g.: cs.uml.edu • leftmost name is typically a host name (has an IP address) • next leftmost name is organization administering that host (e.g., UML C.Sc. Dept.) • next leftmost name is organization administering all of subnames to the left • rightmost (highest) domain: organization, structure, country Socket API2: Application Layer
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 the local nameserver via port 53 • name server returns IP address of requested hostname Socket API2: Application Layer
DNS: non-local names finding non-local names • no single name server has complete information table • 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., uml.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 Socket API2: Application Layer
Assigning a 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 are to be delivered to(demultiplexed to) this socket . Incoming are from a specific remote port and IP address • a return address for outgoing messages Socket API2: Application Layer
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 */ }; Socket API2: Application Layer
The bind() system call int bind ( int sockfd, struct sockaddr *myaddr, int addresslen) • sockfdis the variable assigned socket() return value. • *myaddr:address ofsockaddr_in structure holding local address info. Must be cast to type sockaddr. • addresslenis the size of the address structure error return indicates port number already in use, out- of-range Socket API2: Application Layer
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 */ } Socket API2: Application Layer
Socket bind ( cont.) Bind a name to a socket #include <sys/socket.h> #include <netinet/in.h> #include <sys/un.h> int bind (s, name, namelen) int s; const struct sockaddr * name; int namelen; where: s Socket to bind name Name to bind to socket namelen Length of name (bytes) Description This call allows a process to establish a link to an underlying TCP or UDP port (in the case of an internet socket) or a link to a path name in the file system (in the case of a UNIX domain socket). In general, a server must use this call to give herself an address, whereas a client is not required to use this call (but may if she so chooses),but is automatically allocated a source port at the time a connect() call is made. It can be seen that the call arguments are the same as those for the connect call. returns: 0 on success, or -1 Socket API2: Application Layer
Listen for connections on a socket int listen (s, backlog) int s; int backlog; where: s File descriptor of socket to listen on. backlog Maximum number of waiting connections. returns: 0 on success, or -1 SYNOPSIS #include <sys/socket.h> #include <netinet/in.h> #include <sys/un.h> int accept (s, addr, addrlen) int s; struct sockaddr * addr; int * addrlen; where: s Socket channel listening for connection requests addr Structure to receive the address of connected peer addrlen On input contains the number of bytes available for the peer address; updated to indicate the number of bytes returned returns: Connected new channel number, or -1 Socket API2: Application Layer
Example With Internet Sockets Client/Server example using internet sockets A "one-time" FTP client /* client.c a minimal FTP client */ /* this version works on all BSD based systems */ #include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <fcntl.h> #include <strings.h> #define MSG_BODY 248 #define MSG_SIZE (MSG_BODY+8) #define PORT 27439 #define SEND 1 #define RECV 2 #define DATA 100 #define END_DATA 101 typedef struct{ int mtype; int msize; char mbody[MSG_BODY]; } MSG; typedef union{ MSG m; char buf[MSG_SIZE]; } MBUF; Socket API2: Application Layer
Client/Server example using internet sockets A "one-time" FTP client main(int argc, char *argv[]) { MSG msg; MBUF raw; int inet_sock, local_file; int type_val, size_val, read_val, local_size; int i,j,k; char *buffer_ptr, *token_ptr, *last_token_ptr; union type_size; struct sockaddr_in inet_telnum; struct hostent *heptr, *gethostbyname(); if((inet_sock=socket(AF_INET, SOCK_STREAM, 0)) == -1){ perror("inet_sock allocation failed: "); exit(1); } if((heptr = gethostbyname( argv[1] )) == NULL){ perror("gethostbyname failed: "); exit(1); } bcopy(heptr->h_addr, &inet_telnum.sin_addr, heptr->h_length); inet_telnum.sin_family = AF_INET; inet_telnum.sin_port = htons( (u_short)PORT ); if(connect(inet_sock, &inet_telnum, sizeof(struct sockaddr_in)) == -1){ perror("inet_sock connect failed: "); exit(2); Socket API2: Application Layer
Client/Server example using internet sockets cont'd A "one-time" FTP client msg.mtype = htonl(RECV); strcpy(msg.mbody, argv[2]); local_size = strlen(argv[2]) +1; msg.msize = htonl(local_size); token_ptr = strtok(argv[2], "/"); do{ if((last_token_ptr = token_ptr) == NULL){ printf("\n *** Illegal path name, terminating\n\n"); exit(2); } } while(token_ptr = strtok(NULL, "/")); if((local_file=open(last_token_ptr, O_RDWR | O_CREAT | O_TRUNC, 0666)) == -1){ perror("local_file open failed: "); exit(3); } if(write(inet_sock, &msg, local_size + (2*sizeof(int))) == -1){ perror("inet_sock write failed: "); exit(3); Socket API2: Application Layer
Client/Server example using internet sockets cont'd A "one-time" FTP client while(1){ for(i=0; i<(2*sizeof(int)); i++){ if(read(inet_sock, raw.buf+i, 1) != 1){ perror("read type_size failed: "); exit(3); } } type_val = ntohl(raw.m.mtype); size_val = ntohl(raw.m.msize); read_val = size_val; buffer_ptr = raw.buf; switch(type_val){ case DATA: while ((j = read(inet_sock, buffer_ptr, read_val)) != read_val){ switch(j){ default: read_val -= j; buffer_ptr +=j; break; case -1: perror("inet_sock read failed: "); exit(3); case 0: printf("unexpected EOF on inet_sock\n"); exit(4); } } if(write(local_file, raw.buf, size_val) == -1){ perror("local write failed: "); exit(3); } break; case END_DATA: printf("transfer of %s completed successfully, goodbye\n",argv[2]); exit(0); default: printf("unknown message type %d size of %d\n",type_val,size_val); printf("this is an unrecoverable error, goodbye\n"); exit(5); } } Socket API2: Application Layer
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 Socket API2: Application Layer
connectionless server, cont. 15 printf("Server: creating socket\n"); 16 if ( (sockid = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { 17 printf("Server: socket error: %d\n",errno); exit(0);} 18 printf("Server: binding my local socket\n"); 19 bzero((char *) &my_addr, sizeof(my_addr)); 20 my_addr.sin_family = AF_INET; 21 my_addr.sin_addr.s_addr = htons(INADDR_ANY); 22 my_addr.sin_port = htons(MY_PORT_ID); Socket API2: Application Layer
Example: connectionless server (cont) 23 if ( (bind(sockid, (struct sockaddr *) &my_addr, 24 sizeof(my_addr)) < 0) ) 25 {printf("Server: bind fail: %d\n",errno); exit(0);} 26 printf("Server: starting blocking message read\n"); 27 nread = recvfrom(sockid,msg,11,0, 28 (struct sockaddr *) &client_addr, &addrlen); 29 printf("Server: return code from read is %d\n", nread); 30 if (nread >0) printf("Server: message is: %.11s\n” ,msg); 31 close(sockid); 32 } Socket API2: Application Layer
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 { Socket API2: Application Layer
connectionless client,cont.1 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); exit(0);} 20 21 printf("Client: binding my local socket\n"); 22 bzero((char *) &my_addr, sizeof(my_addr)); 23 my_addr.sin_family = AF_INET; 24 my_addr.sin_addr.s_addr = htonl(INADDR_ANY); 25 my_addr.sin_port = htons(MY_PORT_ID); 26 if ( ( bind(sockid, (struct sockaddr *) &my_addr, 27 sizeof(my_addr)) < 0) ) 28 { printf("Client: bind fail: %d\n",errno);exit(0);} 29 Socket API2: Application Layer
connectionless client , 2 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, 39 sizeof(server_addr)); 40 if (retcode <= -1){ 41 printf("client: sendto failed: %d\n",errno);exit(0);} 42 43 /* close socket */ 44 close(sockid); 45 } Socket API2: Application Layer
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 Socket API2: Application Layer
Connection-oriented service Socket API2: Application Layer
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() Socket API2: Application Layer
Connection-oriented service • client/server handshaking: • client must explicitly connect to server before sending or receiving data (unlike connectionless service case) • 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 and stream-oriented. Socket API2: Application Layer
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 Socket API2: Application Layer
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 Socket API2: Application Layer
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 anaccept().Typical value is 5. Socket API2: Application Layer
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 AND creates other (new) sockets for communication with clients • server can not selectively accept() connection requests • typically handled FCFS. Socket API2: Application Layer
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.- a different socket • addresslen is size of address structure. A value-result argument (set before call, reset during call). Socket API2: Application Layer
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 */ Socket API2: Application Layer