700 likes | 709 Views
This introduction provides an overview of socket programming and implementation issues. It covers the application programming interface (API), including the SOCKET API, and explores topics such as connection management, message transfer, and communication flexibility.
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 }